aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/soc/fsl/guts.c
diff options
context:
space:
mode:
authoryangbo lu <yangbo.lu@nxp.com>2016-11-08 22:14:08 -0500
committerUlf Hansson <ulf.hansson@linaro.org>2016-11-29 03:17:20 -0500
commita6fc3b698130230a2342baacd7821eea0405154c (patch)
tree37edafb8747b0d0e22cdd68d02705ff43eecb7b1 /drivers/soc/fsl/guts.c
parenta8c759c78f709a8c0642a67debf88ec597d74757 (diff)
soc: fsl: add GUTS driver for QorIQ platforms
The global utilities block controls power management, I/O device enabling, power-onreset(POR) configuration monitoring, alternate function selection for multiplexed signals,and clock control. This patch adds a driver to manage and access global utilities block. Initially only reading SVR and registering soc device are supported. Other guts accesses, such as reading RCW, should eventually be moved into this driver as well. Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/soc/fsl/guts.c')
-rw-r--r--drivers/soc/fsl/guts.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
new file mode 100644
index 000000000000..0ac88263c2d7
--- /dev/null
+++ b/drivers/soc/fsl/guts.c
@@ -0,0 +1,236 @@
1/*
2 * Freescale QorIQ Platforms GUTS Driver
3 *
4 * Copyright (C) 2016 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/io.h>
13#include <linux/slab.h>
14#include <linux/module.h>
15#include <linux/of_fdt.h>
16#include <linux/sys_soc.h>
17#include <linux/of_address.h>
18#include <linux/platform_device.h>
19#include <linux/fsl/guts.h>
20
21struct guts {
22 struct ccsr_guts __iomem *regs;
23 bool little_endian;
24};
25
26struct fsl_soc_die_attr {
27 char *die;
28 u32 svr;
29 u32 mask;
30};
31
32static struct guts *guts;
33static struct soc_device_attribute soc_dev_attr;
34static struct soc_device *soc_dev;
35
36
37/* SoC die attribute definition for QorIQ platform */
38static const struct fsl_soc_die_attr fsl_soc_die[] = {
39 /*
40 * Power Architecture-based SoCs T Series
41 */
42
43 /* Die: T4240, SoC: T4240/T4160/T4080 */
44 { .die = "T4240",
45 .svr = 0x82400000,
46 .mask = 0xfff00000,
47 },
48 /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
49 { .die = "T1040",
50 .svr = 0x85200000,
51 .mask = 0xfff00000,
52 },
53 /* Die: T2080, SoC: T2080/T2081 */
54 { .die = "T2080",
55 .svr = 0x85300000,
56 .mask = 0xfff00000,
57 },
58 /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
59 { .die = "T1024",
60 .svr = 0x85400000,
61 .mask = 0xfff00000,
62 },
63
64 /*
65 * ARM-based SoCs LS Series
66 */
67
68 /* Die: LS1043A, SoC: LS1043A/LS1023A */
69 { .die = "LS1043A",
70 .svr = 0x87920000,
71 .mask = 0xffff0000,
72 },
73 /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
74 { .die = "LS2080A",
75 .svr = 0x87010000,
76 .mask = 0xff3f0000,
77 },
78 /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
79 { .die = "LS1088A",
80 .svr = 0x87030000,
81 .mask = 0xff3f0000,
82 },
83 /* Die: LS1012A, SoC: LS1012A */
84 { .die = "LS1012A",
85 .svr = 0x87040000,
86 .mask = 0xffff0000,
87 },
88 /* Die: LS1046A, SoC: LS1046A/LS1026A */
89 { .die = "LS1046A",
90 .svr = 0x87070000,
91 .mask = 0xffff0000,
92 },
93 /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
94 { .die = "LS2088A",
95 .svr = 0x87090000,
96 .mask = 0xff3f0000,
97 },
98 /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
99 { .die = "LS1021A",
100 .svr = 0x87000000,
101 .mask = 0xfff70000,
102 },
103 { },
104};
105
106static const struct fsl_soc_die_attr *fsl_soc_die_match(
107 u32 svr, const struct fsl_soc_die_attr *matches)
108{
109 while (matches->svr) {
110 if (matches->svr == (svr & matches->mask))
111 return matches;
112 matches++;
113 };
114 return NULL;
115}
116
117u32 fsl_guts_get_svr(void)
118{
119 u32 svr = 0;
120
121 if (!guts || !guts->regs)
122 return svr;
123
124 if (guts->little_endian)
125 svr = ioread32(&guts->regs->svr);
126 else
127 svr = ioread32be(&guts->regs->svr);
128
129 return svr;
130}
131EXPORT_SYMBOL(fsl_guts_get_svr);
132
133static int fsl_guts_probe(struct platform_device *pdev)
134{
135 struct device_node *np = pdev->dev.of_node;
136 struct device *dev = &pdev->dev;
137 struct resource *res;
138 const struct fsl_soc_die_attr *soc_die;
139 const char *machine;
140 u32 svr;
141
142 /* Initialize guts */
143 guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
144 if (!guts)
145 return -ENOMEM;
146
147 guts->little_endian = of_property_read_bool(np, "little-endian");
148
149 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
150 guts->regs = devm_ioremap_resource(dev, res);
151 if (IS_ERR(guts->regs))
152 return PTR_ERR(guts->regs);
153
154 /* Register soc device */
155 machine = of_flat_dt_get_machine_name();
156 if (machine)
157 soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
158
159 svr = fsl_guts_get_svr();
160 soc_die = fsl_soc_die_match(svr, fsl_soc_die);
161 if (soc_die) {
162 soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
163 "QorIQ %s", soc_die->die);
164 } else {
165 soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ");
166 }
167 soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
168 "svr:0x%08x", svr);
169 soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
170 (svr >> 4) & 0xf, svr & 0xf);
171
172 soc_dev = soc_device_register(&soc_dev_attr);
173 if (IS_ERR(soc_dev))
174 return PTR_ERR(soc_dev);
175
176 pr_info("Machine: %s\n", soc_dev_attr.machine);
177 pr_info("SoC family: %s\n", soc_dev_attr.family);
178 pr_info("SoC ID: %s, Revision: %s\n",
179 soc_dev_attr.soc_id, soc_dev_attr.revision);
180 return 0;
181}
182
183static int fsl_guts_remove(struct platform_device *dev)
184{
185 soc_device_unregister(soc_dev);
186 return 0;
187}
188
189/*
190 * Table for matching compatible strings, for device tree
191 * guts node, for Freescale QorIQ SOCs.
192 */
193static const struct of_device_id fsl_guts_of_match[] = {
194 { .compatible = "fsl,qoriq-device-config-1.0", },
195 { .compatible = "fsl,qoriq-device-config-2.0", },
196 { .compatible = "fsl,p1010-guts", },
197 { .compatible = "fsl,p1020-guts", },
198 { .compatible = "fsl,p1021-guts", },
199 { .compatible = "fsl,p1022-guts", },
200 { .compatible = "fsl,p1023-guts", },
201 { .compatible = "fsl,p2020-guts", },
202 { .compatible = "fsl,bsc9131-guts", },
203 { .compatible = "fsl,bsc9132-guts", },
204 { .compatible = "fsl,mpc8536-guts", },
205 { .compatible = "fsl,mpc8544-guts", },
206 { .compatible = "fsl,mpc8548-guts", },
207 { .compatible = "fsl,mpc8568-guts", },
208 { .compatible = "fsl,mpc8569-guts", },
209 { .compatible = "fsl,mpc8572-guts", },
210 { .compatible = "fsl,ls1021a-dcfg", },
211 { .compatible = "fsl,ls1043a-dcfg", },
212 { .compatible = "fsl,ls2080a-dcfg", },
213 {}
214};
215MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
216
217static struct platform_driver fsl_guts_driver = {
218 .driver = {
219 .name = "fsl-guts",
220 .of_match_table = fsl_guts_of_match,
221 },
222 .probe = fsl_guts_probe,
223 .remove = fsl_guts_remove,
224};
225
226static int __init fsl_guts_init(void)
227{
228 return platform_driver_register(&fsl_guts_driver);
229}
230core_initcall(fsl_guts_init);
231
232static void __exit fsl_guts_exit(void)
233{
234 platform_driver_unregister(&fsl_guts_driver);
235}
236module_exit(fsl_guts_exit);