Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Freescale QorIQ Platforms GUTS Driver
  4 *
  5 * Copyright (C) 2016 Freescale Semiconductor, Inc.
  6 */
  7
  8#include <linux/io.h>
  9#include <linux/slab.h>
 10#include <linux/module.h>
 11#include <linux/of_fdt.h>
 12#include <linux/sys_soc.h>
 13#include <linux/of_address.h>
 14#include <linux/platform_device.h>
 15#include <linux/fsl/guts.h>
 16
 
 
 
 
 
 17struct fsl_soc_die_attr {
 18	char	*die;
 19	u32	svr;
 20	u32	mask;
 21};
 22
 23struct fsl_soc_data {
 24	const char *sfp_compat;
 25	u32 uid_offset;
 26};
 
 27
 28/* SoC die attribute definition for QorIQ platform */
 29static const struct fsl_soc_die_attr fsl_soc_die[] = {
 30	/*
 31	 * Power Architecture-based SoCs T Series
 32	 */
 33
 34	/* Die: T4240, SoC: T4240/T4160/T4080 */
 35	{ .die		= "T4240",
 36	  .svr		= 0x82400000,
 37	  .mask		= 0xfff00000,
 38	},
 39	/* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
 40	{ .die		= "T1040",
 41	  .svr		= 0x85200000,
 42	  .mask		= 0xfff00000,
 43	},
 44	/* Die: T2080, SoC: T2080/T2081 */
 45	{ .die		= "T2080",
 46	  .svr		= 0x85300000,
 47	  .mask		= 0xfff00000,
 48	},
 49	/* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
 50	{ .die		= "T1024",
 51	  .svr		= 0x85400000,
 52	  .mask		= 0xfff00000,
 53	},
 54
 55	/*
 56	 * ARM-based SoCs LS Series
 57	 */
 58
 59	/* Die: LS1043A, SoC: LS1043A/LS1023A */
 60	{ .die		= "LS1043A",
 61	  .svr		= 0x87920000,
 62	  .mask		= 0xffff0000,
 63	},
 64	/* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
 65	{ .die		= "LS2080A",
 66	  .svr		= 0x87010000,
 67	  .mask		= 0xff3f0000,
 68	},
 69	/* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
 70	{ .die		= "LS1088A",
 71	  .svr		= 0x87030000,
 72	  .mask		= 0xff3f0000,
 73	},
 74	/* Die: LS1012A, SoC: LS1012A */
 75	{ .die		= "LS1012A",
 76	  .svr		= 0x87040000,
 77	  .mask		= 0xffff0000,
 78	},
 79	/* Die: LS1046A, SoC: LS1046A/LS1026A */
 80	{ .die		= "LS1046A",
 81	  .svr		= 0x87070000,
 82	  .mask		= 0xffff0000,
 83	},
 84	/* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
 85	{ .die		= "LS2088A",
 86	  .svr		= 0x87090000,
 87	  .mask		= 0xff3f0000,
 88	},
 89	/* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
 90	{ .die		= "LS1021A",
 91	  .svr		= 0x87000000,
 92	  .mask		= 0xfff70000,
 93	},
 94	/* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */
 95	{ .die          = "LX2160A",
 96	  .svr          = 0x87360000,
 97	  .mask         = 0xff3f0000,
 98	},
 99	/* Die: LS1028A, SoC: LS1028A */
100	{ .die          = "LS1028A",
101	  .svr          = 0x870b0000,
102	  .mask         = 0xff3f0000,
103	},
104	{ },
105};
106
107static const struct fsl_soc_die_attr *fsl_soc_die_match(
108	u32 svr, const struct fsl_soc_die_attr *matches)
109{
110	while (matches->svr) {
111		if (matches->svr == (svr & matches->mask))
112			return matches;
113		matches++;
114	}
115	return NULL;
116}
117
118static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
119{
120	struct device_node *np;
121	void __iomem *sfp_base;
122	u64 uid;
123
124	np = of_find_compatible_node(NULL, NULL, compat);
125	if (!np)
126		return 0;
127
128	sfp_base = of_iomap(np, 0);
129	if (!sfp_base) {
130		of_node_put(np);
131		return 0;
132	}
133
134	uid = ioread32(sfp_base + offset);
135	uid <<= 32;
136	uid |= ioread32(sfp_base + offset + 4);
137
138	iounmap(sfp_base);
139	of_node_put(np);
 
 
140
141	return uid;
142}
143
144static const struct fsl_soc_data ls1028a_data = {
145	.sfp_compat = "fsl,ls1028a-sfp",
146	.uid_offset = 0x21c,
147};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
149/*
150 * Table for matching compatible strings, for device tree
151 * guts node, for Freescale QorIQ SOCs.
152 */
153static const struct of_device_id fsl_guts_of_match[] = {
154	{ .compatible = "fsl,qoriq-device-config-1.0", },
155	{ .compatible = "fsl,qoriq-device-config-2.0", },
156	{ .compatible = "fsl,p1010-guts", },
157	{ .compatible = "fsl,p1020-guts", },
158	{ .compatible = "fsl,p1021-guts", },
159	{ .compatible = "fsl,p1022-guts", },
160	{ .compatible = "fsl,p1023-guts", },
161	{ .compatible = "fsl,p2020-guts", },
162	{ .compatible = "fsl,bsc9131-guts", },
163	{ .compatible = "fsl,bsc9132-guts", },
164	{ .compatible = "fsl,mpc8536-guts", },
165	{ .compatible = "fsl,mpc8544-guts", },
166	{ .compatible = "fsl,mpc8548-guts", },
167	{ .compatible = "fsl,mpc8568-guts", },
168	{ .compatible = "fsl,mpc8569-guts", },
169	{ .compatible = "fsl,mpc8572-guts", },
170	{ .compatible = "fsl,ls1021a-dcfg", },
171	{ .compatible = "fsl,ls1043a-dcfg", },
172	{ .compatible = "fsl,ls2080a-dcfg", },
173	{ .compatible = "fsl,ls1088a-dcfg", },
174	{ .compatible = "fsl,ls1012a-dcfg", },
175	{ .compatible = "fsl,ls1046a-dcfg", },
176	{ .compatible = "fsl,lx2160a-dcfg", },
177	{ .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data},
178	{}
179};
 
 
 
 
 
 
 
 
 
 
180
181static int __init fsl_guts_init(void)
182{
183	struct soc_device_attribute *soc_dev_attr;
184	static struct soc_device *soc_dev;
185	const struct fsl_soc_die_attr *soc_die;
186	const struct fsl_soc_data *soc_data;
187	const struct of_device_id *match;
188	struct ccsr_guts __iomem *regs;
189	const char *machine = NULL;
190	struct device_node *np;
191	bool little_endian;
192	u64 soc_uid = 0;
193	u32 svr;
194	int ret;
195
196	np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
197	if (!np)
198		return 0;
199	soc_data = match->data;
200
201	regs = of_iomap(np, 0);
202	if (!regs) {
203		of_node_put(np);
204		return -ENOMEM;
205	}
206
207	little_endian = of_property_read_bool(np, "little-endian");
208	if (little_endian)
209		svr = ioread32(&regs->svr);
210	else
211		svr = ioread32be(&regs->svr);
212	iounmap(regs);
213	of_node_put(np);
214
215	/* Register soc device */
216	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
217	if (!soc_dev_attr)
218		return -ENOMEM;
219
220	if (of_property_read_string(of_root, "model", &machine))
221		of_property_read_string_index(of_root, "compatible", 0, &machine);
222	if (machine) {
223		soc_dev_attr->machine = kstrdup(machine, GFP_KERNEL);
224		if (!soc_dev_attr->machine)
225			goto err_nomem;
226	}
227
228	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
229	if (soc_die) {
230		soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s",
231						 soc_die->die);
232	} else {
233		soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ");
234	}
235	if (!soc_dev_attr->family)
236		goto err_nomem;
237
238	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
239	if (!soc_dev_attr->soc_id)
240		goto err_nomem;
241
242	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
243					   (svr >>  4) & 0xf, svr & 0xf);
244	if (!soc_dev_attr->revision)
245		goto err_nomem;
246
247	if (soc_data)
248		soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
249					       soc_data->uid_offset);
250	if (soc_uid)
251		soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
252							soc_uid);
253
254	soc_dev = soc_device_register(soc_dev_attr);
255	if (IS_ERR(soc_dev)) {
256		ret = PTR_ERR(soc_dev);
257		goto err;
258	}
259
260	pr_info("Machine: %s\n", soc_dev_attr->machine);
261	pr_info("SoC family: %s\n", soc_dev_attr->family);
262	pr_info("SoC ID: %s, Revision: %s\n",
263		soc_dev_attr->soc_id, soc_dev_attr->revision);
264
265	return 0;
266
267err_nomem:
268	ret = -ENOMEM;
269err:
270	kfree(soc_dev_attr->machine);
271	kfree(soc_dev_attr->family);
272	kfree(soc_dev_attr->soc_id);
273	kfree(soc_dev_attr->revision);
274	kfree(soc_dev_attr->serial_number);
275	kfree(soc_dev_attr);
276
277	return ret;
278}
279core_initcall(fsl_guts_init);
v5.4
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Freescale QorIQ Platforms GUTS Driver
  4 *
  5 * Copyright (C) 2016 Freescale Semiconductor, Inc.
  6 */
  7
  8#include <linux/io.h>
  9#include <linux/slab.h>
 10#include <linux/module.h>
 11#include <linux/of_fdt.h>
 12#include <linux/sys_soc.h>
 13#include <linux/of_address.h>
 14#include <linux/platform_device.h>
 15#include <linux/fsl/guts.h>
 16
 17struct guts {
 18	struct ccsr_guts __iomem *regs;
 19	bool little_endian;
 20};
 21
 22struct fsl_soc_die_attr {
 23	char	*die;
 24	u32	svr;
 25	u32	mask;
 26};
 27
 28static struct guts *guts;
 29static struct soc_device_attribute soc_dev_attr;
 30static struct soc_device *soc_dev;
 31static struct device_node *root;
 32
 33
 34/* SoC die attribute definition for QorIQ platform */
 35static const struct fsl_soc_die_attr fsl_soc_die[] = {
 36	/*
 37	 * Power Architecture-based SoCs T Series
 38	 */
 39
 40	/* Die: T4240, SoC: T4240/T4160/T4080 */
 41	{ .die		= "T4240",
 42	  .svr		= 0x82400000,
 43	  .mask		= 0xfff00000,
 44	},
 45	/* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
 46	{ .die		= "T1040",
 47	  .svr		= 0x85200000,
 48	  .mask		= 0xfff00000,
 49	},
 50	/* Die: T2080, SoC: T2080/T2081 */
 51	{ .die		= "T2080",
 52	  .svr		= 0x85300000,
 53	  .mask		= 0xfff00000,
 54	},
 55	/* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
 56	{ .die		= "T1024",
 57	  .svr		= 0x85400000,
 58	  .mask		= 0xfff00000,
 59	},
 60
 61	/*
 62	 * ARM-based SoCs LS Series
 63	 */
 64
 65	/* Die: LS1043A, SoC: LS1043A/LS1023A */
 66	{ .die		= "LS1043A",
 67	  .svr		= 0x87920000,
 68	  .mask		= 0xffff0000,
 69	},
 70	/* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
 71	{ .die		= "LS2080A",
 72	  .svr		= 0x87010000,
 73	  .mask		= 0xff3f0000,
 74	},
 75	/* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
 76	{ .die		= "LS1088A",
 77	  .svr		= 0x87030000,
 78	  .mask		= 0xff3f0000,
 79	},
 80	/* Die: LS1012A, SoC: LS1012A */
 81	{ .die		= "LS1012A",
 82	  .svr		= 0x87040000,
 83	  .mask		= 0xffff0000,
 84	},
 85	/* Die: LS1046A, SoC: LS1046A/LS1026A */
 86	{ .die		= "LS1046A",
 87	  .svr		= 0x87070000,
 88	  .mask		= 0xffff0000,
 89	},
 90	/* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
 91	{ .die		= "LS2088A",
 92	  .svr		= 0x87090000,
 93	  .mask		= 0xff3f0000,
 94	},
 95	/* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
 96	{ .die		= "LS1021A",
 97	  .svr		= 0x87000000,
 98	  .mask		= 0xfff70000,
 99	},
100	/* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */
101	{ .die          = "LX2160A",
102	  .svr          = 0x87360000,
103	  .mask         = 0xff3f0000,
104	},
105	/* Die: LS1028A, SoC: LS1028A */
106	{ .die          = "LS1028A",
107	  .svr          = 0x870b0000,
108	  .mask         = 0xff3f0000,
109	},
110	{ },
111};
112
113static const struct fsl_soc_die_attr *fsl_soc_die_match(
114	u32 svr, const struct fsl_soc_die_attr *matches)
115{
116	while (matches->svr) {
117		if (matches->svr == (svr & matches->mask))
118			return matches;
119		matches++;
120	};
121	return NULL;
122}
123
124static u32 fsl_guts_get_svr(void)
125{
126	u32 svr = 0;
 
 
 
 
 
 
 
 
 
 
 
 
127
128	if (!guts || !guts->regs)
129		return svr;
 
130
131	if (guts->little_endian)
132		svr = ioread32(&guts->regs->svr);
133	else
134		svr = ioread32be(&guts->regs->svr);
135
136	return svr;
137}
138
139static int fsl_guts_probe(struct platform_device *pdev)
140{
141	struct device_node *np = pdev->dev.of_node;
142	struct device *dev = &pdev->dev;
143	struct resource *res;
144	const struct fsl_soc_die_attr *soc_die;
145	const char *machine;
146	u32 svr;
147
148	/* Initialize guts */
149	guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
150	if (!guts)
151		return -ENOMEM;
152
153	guts->little_endian = of_property_read_bool(np, "little-endian");
154
155	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
156	guts->regs = devm_ioremap_resource(dev, res);
157	if (IS_ERR(guts->regs))
158		return PTR_ERR(guts->regs);
159
160	/* Register soc device */
161	root = of_find_node_by_path("/");
162	if (of_property_read_string(root, "model", &machine))
163		of_property_read_string_index(root, "compatible", 0, &machine);
164	if (machine)
165		soc_dev_attr.machine = machine;
166
167	svr = fsl_guts_get_svr();
168	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
169	if (soc_die) {
170		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
171						     "QorIQ %s", soc_die->die);
172	} else {
173		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ");
174	}
175	if (!soc_dev_attr.family)
176		return -ENOMEM;
177	soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
178					     "svr:0x%08x", svr);
179	if (!soc_dev_attr.soc_id)
180		return -ENOMEM;
181	soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
182					       (svr >>  4) & 0xf, svr & 0xf);
183	if (!soc_dev_attr.revision)
184		return -ENOMEM;
185
186	soc_dev = soc_device_register(&soc_dev_attr);
187	if (IS_ERR(soc_dev))
188		return PTR_ERR(soc_dev);
189
190	pr_info("Machine: %s\n", soc_dev_attr.machine);
191	pr_info("SoC family: %s\n", soc_dev_attr.family);
192	pr_info("SoC ID: %s, Revision: %s\n",
193		soc_dev_attr.soc_id, soc_dev_attr.revision);
194	return 0;
195}
196
197static int fsl_guts_remove(struct platform_device *dev)
198{
199	soc_device_unregister(soc_dev);
200	of_node_put(root);
201	return 0;
202}
203
204/*
205 * Table for matching compatible strings, for device tree
206 * guts node, for Freescale QorIQ SOCs.
207 */
208static const struct of_device_id fsl_guts_of_match[] = {
209	{ .compatible = "fsl,qoriq-device-config-1.0", },
210	{ .compatible = "fsl,qoriq-device-config-2.0", },
211	{ .compatible = "fsl,p1010-guts", },
212	{ .compatible = "fsl,p1020-guts", },
213	{ .compatible = "fsl,p1021-guts", },
214	{ .compatible = "fsl,p1022-guts", },
215	{ .compatible = "fsl,p1023-guts", },
216	{ .compatible = "fsl,p2020-guts", },
217	{ .compatible = "fsl,bsc9131-guts", },
218	{ .compatible = "fsl,bsc9132-guts", },
219	{ .compatible = "fsl,mpc8536-guts", },
220	{ .compatible = "fsl,mpc8544-guts", },
221	{ .compatible = "fsl,mpc8548-guts", },
222	{ .compatible = "fsl,mpc8568-guts", },
223	{ .compatible = "fsl,mpc8569-guts", },
224	{ .compatible = "fsl,mpc8572-guts", },
225	{ .compatible = "fsl,ls1021a-dcfg", },
226	{ .compatible = "fsl,ls1043a-dcfg", },
227	{ .compatible = "fsl,ls2080a-dcfg", },
228	{ .compatible = "fsl,ls1088a-dcfg", },
229	{ .compatible = "fsl,ls1012a-dcfg", },
230	{ .compatible = "fsl,ls1046a-dcfg", },
231	{ .compatible = "fsl,lx2160a-dcfg", },
232	{ .compatible = "fsl,ls1028a-dcfg", },
233	{}
234};
235MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
236
237static struct platform_driver fsl_guts_driver = {
238	.driver = {
239		.name = "fsl-guts",
240		.of_match_table = fsl_guts_of_match,
241	},
242	.probe = fsl_guts_probe,
243	.remove = fsl_guts_remove,
244};
245
246static int __init fsl_guts_init(void)
247{
248	return platform_driver_register(&fsl_guts_driver);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249}
250core_initcall(fsl_guts_init);
251
252static void __exit fsl_guts_exit(void)
253{
254	platform_driver_unregister(&fsl_guts_driver);
255}
256module_exit(fsl_guts_exit);