aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firmware/imx/Makefile2
-rw-r--r--drivers/firmware/imx/imx-scu-irq.c168
-rw-r--r--drivers/firmware/imx/imx-scu.c6
-rw-r--r--drivers/firmware/imx/scu-pd.c121
-rw-r--r--drivers/soc/imx/Makefile1
-rw-r--r--drivers/soc/imx/gpc.c4
-rw-r--r--drivers/soc/imx/gpcv2.c43
-rw-r--r--drivers/soc/imx/soc-imx8.c115
8 files changed, 371 insertions, 89 deletions
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
index 1b2e15b3c9ca..802c4ad8e8f9 100644
--- a/drivers/firmware/imx/Makefile
+++ b/drivers/firmware/imx/Makefile
@@ -1,3 +1,3 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o 2obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o
3obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o 3obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o
diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c
new file mode 100644
index 000000000000..043833ad3c1a
--- /dev/null
+++ b/drivers/firmware/imx/imx-scu-irq.c
@@ -0,0 +1,168 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 NXP
4 *
5 * Implementation of the SCU IRQ functions using MU.
6 *
7 */
8
9#include <dt-bindings/firmware/imx/rsrc.h>
10#include <linux/firmware/imx/ipc.h>
11#include <linux/mailbox_client.h>
12
13#define IMX_SC_IRQ_FUNC_ENABLE 1
14#define IMX_SC_IRQ_FUNC_STATUS 2
15#define IMX_SC_IRQ_NUM_GROUP 4
16
17static u32 mu_resource_id;
18
19struct imx_sc_msg_irq_get_status {
20 struct imx_sc_rpc_msg hdr;
21 union {
22 struct {
23 u16 resource;
24 u8 group;
25 u8 reserved;
26 } __packed req;
27 struct {
28 u32 status;
29 } resp;
30 } data;
31};
32
33struct imx_sc_msg_irq_enable {
34 struct imx_sc_rpc_msg hdr;
35 u32 mask;
36 u16 resource;
37 u8 group;
38 u8 enable;
39} __packed;
40
41static struct imx_sc_ipc *imx_sc_irq_ipc_handle;
42static struct work_struct imx_sc_irq_work;
43static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain);
44
45int imx_scu_irq_register_notifier(struct notifier_block *nb)
46{
47 return atomic_notifier_chain_register(
48 &imx_scu_irq_notifier_chain, nb);
49}
50EXPORT_SYMBOL(imx_scu_irq_register_notifier);
51
52int imx_scu_irq_unregister_notifier(struct notifier_block *nb)
53{
54 return atomic_notifier_chain_unregister(
55 &imx_scu_irq_notifier_chain, nb);
56}
57EXPORT_SYMBOL(imx_scu_irq_unregister_notifier);
58
59static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group)
60{
61 return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain,
62 status, (void *)group);
63}
64
65static void imx_scu_irq_work_handler(struct work_struct *work)
66{
67 struct imx_sc_msg_irq_get_status msg;
68 struct imx_sc_rpc_msg *hdr = &msg.hdr;
69 u32 irq_status;
70 int ret;
71 u8 i;
72
73 for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) {
74 hdr->ver = IMX_SC_RPC_VERSION;
75 hdr->svc = IMX_SC_RPC_SVC_IRQ;
76 hdr->func = IMX_SC_IRQ_FUNC_STATUS;
77 hdr->size = 2;
78
79 msg.data.req.resource = mu_resource_id;
80 msg.data.req.group = i;
81
82 ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
83 if (ret) {
84 pr_err("get irq group %d status failed, ret %d\n",
85 i, ret);
86 return;
87 }
88
89 irq_status = msg.data.resp.status;
90 if (!irq_status)
91 continue;
92
93 imx_scu_irq_notifier_call_chain(irq_status, &i);
94 }
95}
96
97int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable)
98{
99 struct imx_sc_msg_irq_enable msg;
100 struct imx_sc_rpc_msg *hdr = &msg.hdr;
101 int ret;
102
103 hdr->ver = IMX_SC_RPC_VERSION;
104 hdr->svc = IMX_SC_RPC_SVC_IRQ;
105 hdr->func = IMX_SC_IRQ_FUNC_ENABLE;
106 hdr->size = 3;
107
108 msg.resource = mu_resource_id;
109 msg.group = group;
110 msg.mask = mask;
111 msg.enable = enable;
112
113 ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
114 if (ret)
115 pr_err("enable irq failed, group %d, mask %d, ret %d\n",
116 group, mask, ret);
117
118 return ret;
119}
120EXPORT_SYMBOL(imx_scu_irq_group_enable);
121
122static void imx_scu_irq_callback(struct mbox_client *c, void *msg)
123{
124 schedule_work(&imx_sc_irq_work);
125}
126
127int imx_scu_enable_general_irq_channel(struct device *dev)
128{
129 struct of_phandle_args spec;
130 struct mbox_client *cl;
131 struct mbox_chan *ch;
132 int ret = 0, i = 0;
133
134 ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle);
135 if (ret)
136 return ret;
137
138 cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL);
139 if (!cl)
140 return -ENOMEM;
141
142 cl->dev = dev;
143 cl->rx_callback = imx_scu_irq_callback;
144
145 /* SCU general IRQ uses general interrupt channel 3 */
146 ch = mbox_request_channel_byname(cl, "gip3");
147 if (IS_ERR(ch)) {
148 ret = PTR_ERR(ch);
149 dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret);
150 devm_kfree(dev, cl);
151 return ret;
152 }
153
154 INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);
155
156 if (!of_parse_phandle_with_args(dev->of_node, "mboxes",
157 "#mbox-cells", 0, &spec))
158 i = of_alias_get_id(spec.np, "mu");
159
160 /* use mu1 as general mu irq channel if failed */
161 if (i < 0)
162 i = 1;
163
164 mu_resource_id = IMX_SC_R_MU_0A + i;
165
166 return ret;
167}
168EXPORT_SYMBOL(imx_scu_enable_general_irq_channel);
diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c
index 2bb1a19c413f..04a24a863d6e 100644
--- a/drivers/firmware/imx/imx-scu.c
+++ b/drivers/firmware/imx/imx-scu.c
@@ -10,6 +10,7 @@
10#include <linux/err.h> 10#include <linux/err.h>
11#include <linux/firmware/imx/types.h> 11#include <linux/firmware/imx/types.h>
12#include <linux/firmware/imx/ipc.h> 12#include <linux/firmware/imx/ipc.h>
13#include <linux/firmware/imx/sci.h>
13#include <linux/interrupt.h> 14#include <linux/interrupt.h>
14#include <linux/irq.h> 15#include <linux/irq.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
@@ -246,6 +247,11 @@ static int imx_scu_probe(struct platform_device *pdev)
246 247
247 imx_sc_ipc_handle = sc_ipc; 248 imx_sc_ipc_handle = sc_ipc;
248 249
250 ret = imx_scu_enable_general_irq_channel(dev);
251 if (ret)
252 dev_warn(dev,
253 "failed to enable general irq channel: %d\n", ret);
254
249 dev_info(dev, "NXP i.MX SCU Initialized\n"); 255 dev_info(dev, "NXP i.MX SCU Initialized\n");
250 256
251 return devm_of_platform_populate(dev); 257 return devm_of_platform_populate(dev);
diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c
index 39a94c7177fc..480cec69e2c9 100644
--- a/drivers/firmware/imx/scu-pd.c
+++ b/drivers/firmware/imx/scu-pd.c
@@ -74,7 +74,10 @@ struct imx_sc_pd_range {
74 char *name; 74 char *name;
75 u32 rsrc; 75 u32 rsrc;
76 u8 num; 76 u8 num;
77
78 /* add domain index */
77 bool postfix; 79 bool postfix;
80 u8 start_from;
78}; 81};
79 82
80struct imx_sc_pd_soc { 83struct imx_sc_pd_soc {
@@ -84,71 +87,75 @@ struct imx_sc_pd_soc {
84 87
85static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { 88static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
86 /* LSIO SS */ 89 /* LSIO SS */
87 { "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 }, 90 { "pwm", IMX_SC_R_PWM_0, 8, true, 0 },
88 { "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 }, 91 { "gpio", IMX_SC_R_GPIO_0, 8, true, 0 },
89 { "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 }, 92 { "gpt", IMX_SC_R_GPT_0, 5, true, 0 },
90 { "lsio-kpp", IMX_SC_R_KPP, 1, 0 }, 93 { "kpp", IMX_SC_R_KPP, 1, false, 0 },
91 { "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 }, 94 { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 },
92 { "lsio-mu", IMX_SC_R_MU_0A, 14, 1 }, 95 { "mu", IMX_SC_R_MU_0A, 14, true, 0 },
93 96
94 /* CONN SS */ 97 /* CONN SS */
95 { "con-usb", IMX_SC_R_USB_0, 2, 1 }, 98 { "usb", IMX_SC_R_USB_0, 2, true, 0 },
96 { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 }, 99 { "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
97 { "con-usb2", IMX_SC_R_USB_2, 1, 0 }, 100 { "usb2", IMX_SC_R_USB_2, 1, false, 0 },
98 { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 }, 101 { "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
99 { "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 }, 102 { "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },
100 { "con-enet", IMX_SC_R_ENET_0, 2, 1 }, 103 { "enet", IMX_SC_R_ENET_0, 2, true, 0 },
101 { "con-nand", IMX_SC_R_NAND, 1, 0 }, 104 { "nand", IMX_SC_R_NAND, 1, false, 0 },
102 { "con-mlb", IMX_SC_R_MLB_0, 1, 1 }, 105 { "mlb", IMX_SC_R_MLB_0, 1, true, 0 },
103 106
104 /* Audio DMA SS */ 107 /* AUDIO SS */
105 { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 }, 108 { "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 },
106 { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 }, 109 { "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 },
107 { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 }, 110 { "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 },
108 { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 }, 111 { "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 },
109 { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 }, 112 { "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
110 { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 }, 113 { "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
111 { "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 }, 114 { "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
112 { "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 }, 115 { "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
113 { "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 }, 116 { "esai0", IMX_SC_R_ESAI_0, 1, false, 0 },
114 { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 }, 117 { "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
115 { "adma-sai", IMX_SC_R_SAI_0, 3, 1 }, 118 { "sai", IMX_SC_R_SAI_0, 3, true, 0 },
116 { "adma-amix", IMX_SC_R_AMIX, 1, 0 }, 119 { "amix", IMX_SC_R_AMIX, 1, false, 0 },
117 { "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 }, 120 { "mqs0", IMX_SC_R_MQS_0, 1, false, 0 },
118 { "adma-dsp", IMX_SC_R_DSP, 1, 0 }, 121 { "dsp", IMX_SC_R_DSP, 1, false, 0 },
119 { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 }, 122 { "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 },
120 { "adma-can", IMX_SC_R_CAN_0, 3, 1 }, 123
121 { "adma-ftm", IMX_SC_R_FTM_0, 2, 1 }, 124 /* DMA SS */
122 { "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 }, 125 { "can", IMX_SC_R_CAN_0, 3, true, 0 },
123 { "adma-adc", IMX_SC_R_ADC_0, 1, 1 }, 126 { "ftm", IMX_SC_R_FTM_0, 2, true, 0 },
124 { "adma-lcd", IMX_SC_R_LCD_0, 1, 1 }, 127 { "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 },
125 { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 }, 128 { "adc", IMX_SC_R_ADC_0, 1, true, 0 },
126 { "adma-lpuart", IMX_SC_R_UART_0, 4, 1 }, 129 { "lcd", IMX_SC_R_LCD_0, 1, true, 0 },
127 { "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 }, 130 { "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
128 131 { "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
129 /* VPU SS */ 132 { "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },
130 { "vpu", IMX_SC_R_VPU, 1, 0 }, 133
131 { "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 }, 134 /* VPU SS */
132 { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 }, 135 { "vpu", IMX_SC_R_VPU, 1, false, 0 },
133 { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 }, 136 { "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
137 { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
138 { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },
134 139
135 /* GPU SS */ 140 /* GPU SS */
136 { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 }, 141 { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },
137 142
138 /* HSIO SS */ 143 /* HSIO SS */
139 { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 }, 144 { "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 },
140 { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 }, 145 { "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 },
141 { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 }, 146 { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 },
147
148 /* MIPI SS */
149 { "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 },
150 { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
151 { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },
142 152
143 /* MIPI/LVDS SS */ 153 /* LVDS SS */
144 { "mipi0", IMX_SC_R_MIPI_0, 1, 0 }, 154 { "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
145 { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 },
146 { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 },
147 { "lvds0", IMX_SC_R_LVDS_0, 1, 0 },
148 155
149 /* DC SS */ 156 /* DC SS */
150 { "dc0", IMX_SC_R_DC_0, 1, 0 }, 157 { "dc0", IMX_SC_R_DC_0, 1, false, 0 },
151 { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 }, 158 { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
152}; 159};
153 160
154static const struct imx_sc_pd_soc imx8qxp_scu_pd = { 161static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
@@ -236,7 +243,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
236 243
237 if (pd_ranges->postfix) 244 if (pd_ranges->postfix)
238 snprintf(sc_pd->name, sizeof(sc_pd->name), 245 snprintf(sc_pd->name, sizeof(sc_pd->name),
239 "%s%i", pd_ranges->name, idx); 246 "%s%i", pd_ranges->name, pd_ranges->start_from + idx);
240 else 247 else
241 snprintf(sc_pd->name, sizeof(sc_pd->name), 248 snprintf(sc_pd->name, sizeof(sc_pd->name),
242 "%s", pd_ranges->name); 249 "%s", pd_ranges->name);
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
index 506a6f3c2b9b..d6b529e06d9a 100644
--- a/drivers/soc/imx/Makefile
+++ b/drivers/soc/imx/Makefile
@@ -1,2 +1,3 @@
1obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o 1obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
2obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o 2obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
3obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c
index 7d14a4b4e82a..a8f1e47ce698 100644
--- a/drivers/soc/imx/gpc.c
+++ b/drivers/soc/imx/gpc.c
@@ -406,7 +406,6 @@ static int imx_gpc_probe(struct platform_device *pdev)
406 const struct imx_gpc_dt_data *of_id_data = of_id->data; 406 const struct imx_gpc_dt_data *of_id_data = of_id->data;
407 struct device_node *pgc_node; 407 struct device_node *pgc_node;
408 struct regmap *regmap; 408 struct regmap *regmap;
409 struct resource *res;
410 void __iomem *base; 409 void __iomem *base;
411 int ret; 410 int ret;
412 411
@@ -417,8 +416,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
417 !pgc_node) 416 !pgc_node)
418 return 0; 417 return 0;
419 418
420 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 419 base = devm_platform_ioremap_resource(pdev, 0);
421 base = devm_ioremap_resource(&pdev->dev, res);
422 if (IS_ERR(base)) 420 if (IS_ERR(base))
423 return PTR_ERR(base); 421 return PTR_ERR(base);
424 422
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index 176f473127b6..31b8d002d855 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -136,8 +136,8 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
136 GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; 136 GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
137 const bool enable_power_control = !on; 137 const bool enable_power_control = !on;
138 const bool has_regulator = !IS_ERR(domain->regulator); 138 const bool has_regulator = !IS_ERR(domain->regulator);
139 unsigned long deadline;
140 int i, ret = 0; 139 int i, ret = 0;
140 u32 pxx_req;
141 141
142 regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 142 regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
143 domain->bits.map, domain->bits.map); 143 domain->bits.map, domain->bits.map);
@@ -169,30 +169,19 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
169 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait 169 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
170 * for PUP_REQ/PDN_REQ bit to be cleared 170 * for PUP_REQ/PDN_REQ bit to be cleared
171 */ 171 */
172 deadline = jiffies + msecs_to_jiffies(1); 172 ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req,
173 while (true) { 173 !(pxx_req & domain->bits.pxx),
174 u32 pxx_req; 174 0, USEC_PER_MSEC);
175 175 if (ret) {
176 regmap_read(domain->regmap, offset, &pxx_req); 176 dev_err(domain->dev, "failed to command PGC\n");
177 177 /*
178 if (!(pxx_req & domain->bits.pxx)) 178 * If we were in a process of enabling a
179 break; 179 * domain and failed we might as well disable
180 180 * the regulator we just enabled. And if it
181 if (time_after(jiffies, deadline)) { 181 * was the opposite situation and we failed to
182 dev_err(domain->dev, "falied to command PGC\n"); 182 * power down -- keep the regulator on
183 ret = -ETIMEDOUT; 183 */
184 /* 184 on = !on;
185 * If we were in a process of enabling a
186 * domain and failed we might as well disable
187 * the regulator we just enabled. And if it
188 * was the opposite situation and we failed to
189 * power down -- keep the regulator on
190 */
191 on = !on;
192 break;
193 }
194
195 cpu_relax();
196 } 185 }
197 186
198 if (enable_power_control) 187 if (enable_power_control)
@@ -574,7 +563,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
574 struct device *dev = &pdev->dev; 563 struct device *dev = &pdev->dev;
575 struct device_node *pgc_np, *np; 564 struct device_node *pgc_np, *np;
576 struct regmap *regmap; 565 struct regmap *regmap;
577 struct resource *res;
578 void __iomem *base; 566 void __iomem *base;
579 int ret; 567 int ret;
580 568
@@ -584,8 +572,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
584 return -EINVAL; 572 return -EINVAL;
585 } 573 }
586 574
587 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 575 base = devm_platform_ioremap_resource(pdev, 0);
588 base = devm_ioremap_resource(dev, res);
589 if (IS_ERR(base)) 576 if (IS_ERR(base))
590 return PTR_ERR(base); 577 return PTR_ERR(base);
591 578
diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c
new file mode 100644
index 000000000000..fc6429f9170a
--- /dev/null
+++ b/drivers/soc/imx/soc-imx8.c
@@ -0,0 +1,115 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2019 NXP.
4 */
5
6#include <linux/init.h>
7#include <linux/io.h>
8#include <linux/of_address.h>
9#include <linux/slab.h>
10#include <linux/sys_soc.h>
11#include <linux/platform_device.h>
12#include <linux/of.h>
13
14#define REV_B1 0x21
15
16#define IMX8MQ_SW_INFO_B1 0x40
17#define IMX8MQ_SW_MAGIC_B1 0xff0055aa
18
19struct imx8_soc_data {
20 char *name;
21 u32 (*soc_revision)(void);
22};
23
24static u32 __init imx8mq_soc_revision(void)
25{
26 struct device_node *np;
27 void __iomem *ocotp_base;
28 u32 magic;
29 u32 rev = 0;
30
31 np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
32 if (!np)
33 goto out;
34
35 ocotp_base = of_iomap(np, 0);
36 WARN_ON(!ocotp_base);
37
38 magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
39 if (magic == IMX8MQ_SW_MAGIC_B1)
40 rev = REV_B1;
41
42 iounmap(ocotp_base);
43
44out:
45 of_node_put(np);
46 return rev;
47}
48
49static const struct imx8_soc_data imx8mq_soc_data = {
50 .name = "i.MX8MQ",
51 .soc_revision = imx8mq_soc_revision,
52};
53
54static const struct of_device_id imx8_soc_match[] = {
55 { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
56 { }
57};
58
59#define imx8_revision(soc_rev) \
60 soc_rev ? \
61 kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \
62 "unknown"
63
64static int __init imx8_soc_init(void)
65{
66 struct soc_device_attribute *soc_dev_attr;
67 struct soc_device *soc_dev;
68 struct device_node *root;
69 const struct of_device_id *id;
70 u32 soc_rev = 0;
71 const struct imx8_soc_data *data;
72 int ret;
73
74 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
75 if (!soc_dev_attr)
76 return -ENODEV;
77
78 soc_dev_attr->family = "Freescale i.MX";
79
80 root = of_find_node_by_path("/");
81 ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
82 if (ret)
83 goto free_soc;
84
85 id = of_match_node(imx8_soc_match, root);
86 if (!id)
87 goto free_soc;
88
89 of_node_put(root);
90
91 data = id->data;
92 if (data) {
93 soc_dev_attr->soc_id = data->name;
94 if (data->soc_revision)
95 soc_rev = data->soc_revision();
96 }
97
98 soc_dev_attr->revision = imx8_revision(soc_rev);
99 if (!soc_dev_attr->revision)
100 goto free_soc;
101
102 soc_dev = soc_device_register(soc_dev_attr);
103 if (IS_ERR(soc_dev))
104 goto free_rev;
105
106 return 0;
107
108free_rev:
109 kfree(soc_dev_attr->revision);
110free_soc:
111 kfree(soc_dev_attr);
112 of_node_put(root);
113 return -ENODEV;
114}
115device_initcall(imx8_soc_init);