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