1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2016 Freescale Semiconductor, Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #include <common.h>
7*4882a593Smuzhiyun #include <asm/io.h>
8*4882a593Smuzhiyun #include <asm/arch/imx-regs.h>
9*4882a593Smuzhiyun #include <asm/mach-imx/rdc-sema.h>
10*4882a593Smuzhiyun #include <asm/arch/imx-rdc.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /*
14*4882a593Smuzhiyun * Check if the RDC Semaphore is required for this peripheral.
15*4882a593Smuzhiyun */
imx_rdc_check_sema_required(int per_id)16*4882a593Smuzhiyun static inline int imx_rdc_check_sema_required(int per_id)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun struct rdc_regs *imx_rdc = (struct rdc_regs *)RDC_BASE_ADDR;
19*4882a593Smuzhiyun u32 reg;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun reg = readl(&imx_rdc->pdap[per_id]);
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun * No semaphore:
24*4882a593Smuzhiyun * Intial value or this peripheral is assigned to only one domain
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun if (!(reg & RDC_PDAP_SREQ_MASK))
27*4882a593Smuzhiyun return -ENOENT;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun return 0;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun * Check the peripheral read / write access permission on Domain [dom_id].
34*4882a593Smuzhiyun */
imx_rdc_check_permission(int per_id,int dom_id)35*4882a593Smuzhiyun int imx_rdc_check_permission(int per_id, int dom_id)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun struct rdc_regs *imx_rdc = (struct rdc_regs *)RDC_BASE_ADDR;
38*4882a593Smuzhiyun u32 reg;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun reg = readl(&imx_rdc->pdap[per_id]);
41*4882a593Smuzhiyun if (!(reg & RDC_PDAP_DRW_MASK(dom_id)))
42*4882a593Smuzhiyun return -EACCES; /*No access*/
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun return 0;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun * Lock up the RDC semaphore for this peripheral if semaphore is required.
49*4882a593Smuzhiyun */
imx_rdc_sema_lock(int per_id)50*4882a593Smuzhiyun int imx_rdc_sema_lock(int per_id)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun struct rdc_sema_regs *imx_rdc_sema;
53*4882a593Smuzhiyun int ret;
54*4882a593Smuzhiyun u8 reg;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun ret = imx_rdc_check_sema_required(per_id);
57*4882a593Smuzhiyun if (ret)
58*4882a593Smuzhiyun return ret;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun if (per_id < SEMA_GATES_NUM)
61*4882a593Smuzhiyun imx_rdc_sema = (struct rdc_sema_regs *)SEMAPHORE1_BASE_ADDR;
62*4882a593Smuzhiyun else
63*4882a593Smuzhiyun imx_rdc_sema = (struct rdc_sema_regs *)SEMAPHORE2_BASE_ADDR;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun do {
66*4882a593Smuzhiyun writeb(RDC_SEMA_PROC_ID,
67*4882a593Smuzhiyun &imx_rdc_sema->gate[per_id % SEMA_GATES_NUM]);
68*4882a593Smuzhiyun reg = readb(&imx_rdc_sema->gate[per_id % SEMA_GATES_NUM]);
69*4882a593Smuzhiyun if ((reg & RDC_SEMA_GATE_GTFSM_MASK) == RDC_SEMA_PROC_ID)
70*4882a593Smuzhiyun break; /* Get the Semaphore*/
71*4882a593Smuzhiyun } while (1);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /*
77*4882a593Smuzhiyun * Unlock the RDC semaphore for this peripheral if main CPU is the
78*4882a593Smuzhiyun * semaphore owner.
79*4882a593Smuzhiyun */
imx_rdc_sema_unlock(int per_id)80*4882a593Smuzhiyun int imx_rdc_sema_unlock(int per_id)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun struct rdc_sema_regs *imx_rdc_sema;
83*4882a593Smuzhiyun int ret;
84*4882a593Smuzhiyun u8 reg;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun ret = imx_rdc_check_sema_required(per_id);
87*4882a593Smuzhiyun if (ret)
88*4882a593Smuzhiyun return ret;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if (per_id < SEMA_GATES_NUM)
91*4882a593Smuzhiyun imx_rdc_sema = (struct rdc_sema_regs *)SEMAPHORE1_BASE_ADDR;
92*4882a593Smuzhiyun else
93*4882a593Smuzhiyun imx_rdc_sema = (struct rdc_sema_regs *)SEMAPHORE2_BASE_ADDR;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun reg = readb(&imx_rdc_sema->gate[per_id % SEMA_GATES_NUM]);
96*4882a593Smuzhiyun if ((reg & RDC_SEMA_GATE_GTFSM_MASK) != RDC_SEMA_PROC_ID)
97*4882a593Smuzhiyun return -EACCES; /*Not the semaphore owner */
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun writeb(0x0, &imx_rdc_sema->gate[per_id % SEMA_GATES_NUM]);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun return 0;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /*
105*4882a593Smuzhiyun * Setup RDC setting for one peripheral
106*4882a593Smuzhiyun */
imx_rdc_setup_peri(rdc_peri_cfg_t p)107*4882a593Smuzhiyun int imx_rdc_setup_peri(rdc_peri_cfg_t p)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun struct rdc_regs *imx_rdc = (struct rdc_regs *)RDC_BASE_ADDR;
110*4882a593Smuzhiyun u32 reg = 0;
111*4882a593Smuzhiyun u32 share_count = 0;
112*4882a593Smuzhiyun u32 peri_id = p & RDC_PERI_MASK;
113*4882a593Smuzhiyun u32 domain = (p & RDC_DOMAIN_MASK) >> RDC_DOMAIN_SHIFT_BASE;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* No domain assigned */
116*4882a593Smuzhiyun if (domain == 0)
117*4882a593Smuzhiyun return -EINVAL;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun reg |= domain;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun share_count = (domain & 0x3)
122*4882a593Smuzhiyun + ((domain >> 2) & 0x3)
123*4882a593Smuzhiyun + ((domain >> 4) & 0x3)
124*4882a593Smuzhiyun + ((domain >> 6) & 0x3);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun if (share_count > 0x3)
127*4882a593Smuzhiyun reg |= RDC_PDAP_SREQ_MASK;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun writel(reg, &imx_rdc->pdap[peri_id]);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return 0;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /*
135*4882a593Smuzhiyun * Setup RDC settings for multiple peripherals
136*4882a593Smuzhiyun */
imx_rdc_setup_peripherals(rdc_peri_cfg_t const * peripherals_list,unsigned count)137*4882a593Smuzhiyun int imx_rdc_setup_peripherals(rdc_peri_cfg_t const *peripherals_list,
138*4882a593Smuzhiyun unsigned count)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun rdc_peri_cfg_t const *p = peripherals_list;
141*4882a593Smuzhiyun int i, ret;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun for (i = 0; i < count; i++) {
144*4882a593Smuzhiyun ret = imx_rdc_setup_peri(*p);
145*4882a593Smuzhiyun if (ret)
146*4882a593Smuzhiyun return ret;
147*4882a593Smuzhiyun p++;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun return 0;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /*
154*4882a593Smuzhiyun * Setup RDC setting for one master
155*4882a593Smuzhiyun */
imx_rdc_setup_ma(rdc_ma_cfg_t p)156*4882a593Smuzhiyun int imx_rdc_setup_ma(rdc_ma_cfg_t p)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun struct rdc_regs *imx_rdc = (struct rdc_regs *)RDC_BASE_ADDR;
159*4882a593Smuzhiyun u32 master_id = (p & RDC_MASTER_MASK) >> RDC_MASTER_SHIFT;
160*4882a593Smuzhiyun u32 domain = (p & RDC_DOMAIN_MASK) >> RDC_DOMAIN_SHIFT_BASE;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun writel((domain & RDC_MDA_DID_MASK), &imx_rdc->mda[master_id]);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun return 0;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun * Setup RDC settings for multiple masters
169*4882a593Smuzhiyun */
imx_rdc_setup_masters(rdc_ma_cfg_t const * masters_list,unsigned count)170*4882a593Smuzhiyun int imx_rdc_setup_masters(rdc_ma_cfg_t const *masters_list, unsigned count)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun rdc_ma_cfg_t const *p = masters_list;
173*4882a593Smuzhiyun int i, ret;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun for (i = 0; i < count; i++) {
176*4882a593Smuzhiyun ret = imx_rdc_setup_ma(*p);
177*4882a593Smuzhiyun if (ret)
178*4882a593Smuzhiyun return ret;
179*4882a593Smuzhiyun p++;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun return 0;
183*4882a593Smuzhiyun }
184