1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2018 NXP 4 * 5 * Peng Fan <peng.fan@nxp.com> 6 */ 7 8 #include <common.h> 9 #include <asm/io.h> 10 #include <dm.h> 11 #include <dm/lists.h> 12 #include <dm/root.h> 13 #include <dm/device-internal.h> 14 #include <asm/arch/sci/sci.h> 15 #include <linux/iopoll.h> 16 #include <misc.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 struct mu_type { 21 u32 tr[4]; 22 u32 rr[4]; 23 u32 sr; 24 u32 cr; 25 }; 26 27 struct imx8_scu { 28 struct mu_type *base; 29 struct udevice *clk; 30 struct udevice *pinclk; 31 }; 32 33 #define MU_CR_GIE_MASK 0xF0000000u 34 #define MU_CR_RIE_MASK 0xF000000u 35 #define MU_CR_GIR_MASK 0xF0000u 36 #define MU_CR_TIE_MASK 0xF00000u 37 #define MU_CR_F_MASK 0x7u 38 #define MU_SR_TE0_MASK BIT(23) 39 #define MU_SR_RF0_MASK BIT(27) 40 #define MU_TR_COUNT 4 41 #define MU_RR_COUNT 4 42 43 static inline void mu_hal_init(struct mu_type *base) 44 { 45 /* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */ 46 clrbits_le32(&base->cr, MU_CR_GIE_MASK | MU_CR_RIE_MASK | 47 MU_CR_TIE_MASK | MU_CR_GIR_MASK | MU_CR_F_MASK); 48 } 49 50 static int mu_hal_sendmsg(struct mu_type *base, u32 reg_index, u32 msg) 51 { 52 u32 mask = MU_SR_TE0_MASK >> reg_index; 53 u32 val; 54 int ret; 55 56 assert(reg_index < MU_TR_COUNT); 57 58 /* Wait TX register to be empty. */ 59 ret = readl_poll_timeout(&base->sr, val, val & mask, 10000); 60 if (ret < 0) { 61 printf("%s timeout\n", __func__); 62 return -ETIMEDOUT; 63 } 64 65 writel(msg, &base->tr[reg_index]); 66 67 return 0; 68 } 69 70 static int mu_hal_receivemsg(struct mu_type *base, u32 reg_index, u32 *msg) 71 { 72 u32 mask = MU_SR_RF0_MASK >> reg_index; 73 u32 val; 74 int ret; 75 76 assert(reg_index < MU_TR_COUNT); 77 78 /* Wait RX register to be full. */ 79 ret = readl_poll_timeout(&base->sr, val, val & mask, 10000); 80 if (ret < 0) { 81 printf("%s timeout\n", __func__); 82 return -ETIMEDOUT; 83 } 84 85 *msg = readl(&base->rr[reg_index]); 86 87 return 0; 88 } 89 90 static int sc_ipc_read(struct mu_type *base, void *data) 91 { 92 struct sc_rpc_msg_s *msg = (struct sc_rpc_msg_s *)data; 93 int ret; 94 u8 count = 0; 95 96 if (!msg) 97 return -EINVAL; 98 99 /* Read first word */ 100 ret = mu_hal_receivemsg(base, 0, (u32 *)msg); 101 if (ret) 102 return ret; 103 count++; 104 105 /* Check size */ 106 if (msg->size > SC_RPC_MAX_MSG) { 107 *((u32 *)msg) = 0; 108 return -EINVAL; 109 } 110 111 /* Read remaining words */ 112 while (count < msg->size) { 113 ret = mu_hal_receivemsg(base, count % MU_RR_COUNT, 114 &msg->DATA.u32[count - 1]); 115 if (ret) 116 return ret; 117 count++; 118 } 119 120 return 0; 121 } 122 123 static int sc_ipc_write(struct mu_type *base, void *data) 124 { 125 struct sc_rpc_msg_s *msg = (struct sc_rpc_msg_s *)data; 126 int ret; 127 u8 count = 0; 128 129 if (!msg) 130 return -EINVAL; 131 132 /* Check size */ 133 if (msg->size > SC_RPC_MAX_MSG) 134 return -EINVAL; 135 136 /* Write first word */ 137 ret = mu_hal_sendmsg(base, 0, *((u32 *)msg)); 138 if (ret) 139 return ret; 140 count++; 141 142 /* Write remaining words */ 143 while (count < msg->size) { 144 ret = mu_hal_sendmsg(base, count % MU_TR_COUNT, 145 msg->DATA.u32[count - 1]); 146 if (ret) 147 return ret; 148 count++; 149 } 150 151 return 0; 152 } 153 154 /* 155 * Note the function prototype use msgid as the 2nd parameter, here 156 * we take it as no_resp. 157 */ 158 static int imx8_scu_call(struct udevice *dev, int no_resp, void *tx_msg, 159 int tx_size, void *rx_msg, int rx_size) 160 { 161 struct imx8_scu *plat = dev_get_platdata(dev); 162 sc_err_t result; 163 int ret; 164 165 /* Expect tx_msg, rx_msg are the same value */ 166 if (rx_msg && tx_msg != rx_msg) 167 printf("tx_msg %p, rx_msg %p\n", tx_msg, rx_msg); 168 169 ret = sc_ipc_write(plat->base, tx_msg); 170 if (ret) 171 return ret; 172 if (!no_resp) { 173 ret = sc_ipc_read(plat->base, rx_msg); 174 if (ret) 175 return ret; 176 } 177 178 result = RPC_R8((struct sc_rpc_msg_s *)tx_msg); 179 180 return sc_err_to_linux(result); 181 } 182 183 static int imx8_scu_probe(struct udevice *dev) 184 { 185 struct imx8_scu *plat = dev_get_platdata(dev); 186 fdt_addr_t addr; 187 188 debug("%s(dev=%p) (plat=%p)\n", __func__, dev, plat); 189 190 addr = devfdt_get_addr(dev); 191 if (addr == FDT_ADDR_T_NONE) 192 return -EINVAL; 193 194 plat->base = (struct mu_type *)addr; 195 196 /* U-Boot not enable interrupts, so need to enable RX interrupts */ 197 mu_hal_init(plat->base); 198 199 gd->arch.scu_dev = dev; 200 201 device_probe(plat->clk); 202 device_probe(plat->pinclk); 203 204 return 0; 205 } 206 207 static int imx8_scu_remove(struct udevice *dev) 208 { 209 return 0; 210 } 211 212 static int imx8_scu_bind(struct udevice *dev) 213 { 214 struct imx8_scu *plat = dev_get_platdata(dev); 215 int ret; 216 struct udevice *child; 217 int node; 218 219 debug("%s(dev=%p)\n", __func__, dev); 220 221 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, 222 "fsl,imx8qxp-clk"); 223 if (node < 0) 224 panic("No clk node found\n"); 225 226 ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true); 227 if (ret) 228 return ret; 229 230 plat->clk = child; 231 232 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, 233 "fsl,imx8qxp-iomuxc"); 234 if (node < 0) 235 panic("No iomuxc node found\n"); 236 237 ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true); 238 if (ret) 239 return ret; 240 241 plat->pinclk = child; 242 243 return 0; 244 } 245 246 static struct misc_ops imx8_scu_ops = { 247 .call = imx8_scu_call, 248 }; 249 250 static const struct udevice_id imx8_scu_ids[] = { 251 { .compatible = "fsl,imx8qxp-mu" }, 252 { .compatible = "fsl,imx8-mu" }, 253 { } 254 }; 255 256 U_BOOT_DRIVER(imx8_scu) = { 257 .name = "imx8_scu", 258 .id = UCLASS_MISC, 259 .of_match = imx8_scu_ids, 260 .probe = imx8_scu_probe, 261 .bind = imx8_scu_bind, 262 .remove = imx8_scu_remove, 263 .ops = &imx8_scu_ops, 264 .platdata_auto_alloc_size = sizeof(struct imx8_scu), 265 .flags = DM_FLAG_PRE_RELOC, 266 }; 267