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