xref: /openbmc/linux/drivers/mfd/ocelot-core.c (revision c21ff093)
1f3e89362SColin Foster // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2f3e89362SColin Foster /*
3f3e89362SColin Foster  * Core driver for the Ocelot chip family.
4f3e89362SColin Foster  *
5f3e89362SColin Foster  * The VSC7511, 7512, 7513, and 7514 can be controlled internally via an
6f3e89362SColin Foster  * on-chip MIPS processor, or externally via SPI, I2C, PCIe. This core driver is
7f3e89362SColin Foster  * intended to be the bus-agnostic glue between, for example, the SPI bus and
8f3e89362SColin Foster  * the child devices.
9f3e89362SColin Foster  *
10f3e89362SColin Foster  * Copyright 2021-2022 Innovative Advantage Inc.
11f3e89362SColin Foster  *
12f3e89362SColin Foster  * Author: Colin Foster <colin.foster@in-advantage.com>
13f3e89362SColin Foster  */
14f3e89362SColin Foster 
15f3e89362SColin Foster #include <linux/bits.h>
16f3e89362SColin Foster #include <linux/device.h>
17f3e89362SColin Foster #include <linux/export.h>
18f3e89362SColin Foster #include <linux/iopoll.h>
19f3e89362SColin Foster #include <linux/ioport.h>
20f3e89362SColin Foster #include <linux/kernel.h>
21f3e89362SColin Foster #include <linux/mfd/core.h>
22f3e89362SColin Foster #include <linux/mfd/ocelot.h>
23f3e89362SColin Foster #include <linux/module.h>
24f3e89362SColin Foster #include <linux/regmap.h>
25f3e89362SColin Foster #include <linux/types.h>
26f3e89362SColin Foster 
27f3e89362SColin Foster #include <soc/mscc/ocelot.h>
28f3e89362SColin Foster 
29f3e89362SColin Foster #include "ocelot.h"
30f3e89362SColin Foster 
31f3e89362SColin Foster #define REG_GCB_SOFT_RST		0x0008
32f3e89362SColin Foster 
33f3e89362SColin Foster #define BIT_SOFT_CHIP_RST		BIT(0)
34f3e89362SColin Foster 
35f3e89362SColin Foster #define VSC7512_MIIM0_RES_START		0x7107009c
36f3e89362SColin Foster #define VSC7512_MIIM1_RES_START		0x710700c0
37fde0b6ceSColin Foster #define VSC7512_MIIM_RES_SIZE		0x00000024
38f3e89362SColin Foster 
39f3e89362SColin Foster #define VSC7512_PHY_RES_START		0x710700f0
40fde0b6ceSColin Foster #define VSC7512_PHY_RES_SIZE		0x00000004
41f3e89362SColin Foster 
42f3e89362SColin Foster #define VSC7512_GPIO_RES_START		0x71070034
43fde0b6ceSColin Foster #define VSC7512_GPIO_RES_SIZE		0x0000006c
44f3e89362SColin Foster 
45f3e89362SColin Foster #define VSC7512_SIO_CTRL_RES_START	0x710700f8
46fde0b6ceSColin Foster #define VSC7512_SIO_CTRL_RES_SIZE	0x00000100
47f3e89362SColin Foster 
48*c21ff093SColin Foster #define VSC7512_HSIO_RES_START		0x710d0000
49*c21ff093SColin Foster #define VSC7512_HSIO_RES_SIZE		0x00000128
50*c21ff093SColin Foster 
518dccdd27SColin Foster #define VSC7512_ANA_RES_START		0x71880000
528dccdd27SColin Foster #define VSC7512_ANA_RES_SIZE		0x00010000
538dccdd27SColin Foster 
548dccdd27SColin Foster #define VSC7512_QS_RES_START		0x71080000
558dccdd27SColin Foster #define VSC7512_QS_RES_SIZE		0x00000100
568dccdd27SColin Foster 
578dccdd27SColin Foster #define VSC7512_QSYS_RES_START		0x71800000
588dccdd27SColin Foster #define VSC7512_QSYS_RES_SIZE		0x00200000
598dccdd27SColin Foster 
608dccdd27SColin Foster #define VSC7512_REW_RES_START		0x71030000
618dccdd27SColin Foster #define VSC7512_REW_RES_SIZE		0x00010000
628dccdd27SColin Foster 
638dccdd27SColin Foster #define VSC7512_SYS_RES_START		0x71010000
648dccdd27SColin Foster #define VSC7512_SYS_RES_SIZE		0x00010000
658dccdd27SColin Foster 
668dccdd27SColin Foster #define VSC7512_S0_RES_START		0x71040000
678dccdd27SColin Foster #define VSC7512_S1_RES_START		0x71050000
688dccdd27SColin Foster #define VSC7512_S2_RES_START		0x71060000
698dccdd27SColin Foster #define VCAP_RES_SIZE			0x00000400
708dccdd27SColin Foster 
718dccdd27SColin Foster #define VSC7512_PORT_0_RES_START	0x711e0000
728dccdd27SColin Foster #define VSC7512_PORT_1_RES_START	0x711f0000
738dccdd27SColin Foster #define VSC7512_PORT_2_RES_START	0x71200000
748dccdd27SColin Foster #define VSC7512_PORT_3_RES_START	0x71210000
758dccdd27SColin Foster #define VSC7512_PORT_4_RES_START	0x71220000
768dccdd27SColin Foster #define VSC7512_PORT_5_RES_START	0x71230000
778dccdd27SColin Foster #define VSC7512_PORT_6_RES_START	0x71240000
788dccdd27SColin Foster #define VSC7512_PORT_7_RES_START	0x71250000
798dccdd27SColin Foster #define VSC7512_PORT_8_RES_START	0x71260000
808dccdd27SColin Foster #define VSC7512_PORT_9_RES_START	0x71270000
818dccdd27SColin Foster #define VSC7512_PORT_10_RES_START	0x71280000
828dccdd27SColin Foster #define VSC7512_PORT_RES_SIZE		0x00010000
838dccdd27SColin Foster 
84f3e89362SColin Foster #define VSC7512_GCB_RST_SLEEP_US	100
85f3e89362SColin Foster #define VSC7512_GCB_RST_TIMEOUT_US	100000
86f3e89362SColin Foster 
ocelot_gcb_chip_rst_status(struct ocelot_ddata * ddata)87f3e89362SColin Foster static int ocelot_gcb_chip_rst_status(struct ocelot_ddata *ddata)
88f3e89362SColin Foster {
89f3e89362SColin Foster 	int val, err;
90f3e89362SColin Foster 
91f3e89362SColin Foster 	err = regmap_read(ddata->gcb_regmap, REG_GCB_SOFT_RST, &val);
92f3e89362SColin Foster 	if (err)
93f3e89362SColin Foster 		return err;
94f3e89362SColin Foster 
95f3e89362SColin Foster 	return val;
96f3e89362SColin Foster }
97f3e89362SColin Foster 
ocelot_chip_reset(struct device * dev)98f3e89362SColin Foster int ocelot_chip_reset(struct device *dev)
99f3e89362SColin Foster {
100f3e89362SColin Foster 	struct ocelot_ddata *ddata = dev_get_drvdata(dev);
101f3e89362SColin Foster 	int ret, val;
102f3e89362SColin Foster 
103f3e89362SColin Foster 	/*
104f3e89362SColin Foster 	 * Reset the entire chip here to put it into a completely known state.
105f3e89362SColin Foster 	 * Other drivers may want to reset their own subsystems. The register
106f3e89362SColin Foster 	 * self-clears, so one write is all that is needed and wait for it to
107f3e89362SColin Foster 	 * clear.
108f3e89362SColin Foster 	 */
109f3e89362SColin Foster 	ret = regmap_write(ddata->gcb_regmap, REG_GCB_SOFT_RST, BIT_SOFT_CHIP_RST);
110f3e89362SColin Foster 	if (ret)
111f3e89362SColin Foster 		return ret;
112f3e89362SColin Foster 
113f3e89362SColin Foster 	return readx_poll_timeout(ocelot_gcb_chip_rst_status, ddata, val, !val,
114f3e89362SColin Foster 				  VSC7512_GCB_RST_SLEEP_US, VSC7512_GCB_RST_TIMEOUT_US);
115f3e89362SColin Foster }
116f3e89362SColin Foster EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT);
117f3e89362SColin Foster 
118f3e89362SColin Foster static const struct resource vsc7512_miim0_resources[] = {
119f3e89362SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"),
120f3e89362SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PHY_RES_START, VSC7512_PHY_RES_SIZE, "gcb_phy"),
121f3e89362SColin Foster };
122f3e89362SColin Foster 
123f3e89362SColin Foster static const struct resource vsc7512_miim1_resources[] = {
124f3e89362SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_MIIM1_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim1"),
125f3e89362SColin Foster };
126f3e89362SColin Foster 
127f3e89362SColin Foster static const struct resource vsc7512_pinctrl_resources[] = {
128f3e89362SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_GPIO_RES_START, VSC7512_GPIO_RES_SIZE, "gcb_gpio"),
129f3e89362SColin Foster };
130f3e89362SColin Foster 
131f3e89362SColin Foster static const struct resource vsc7512_sgpio_resources[] = {
132f3e89362SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_SIO_CTRL_RES_START, VSC7512_SIO_CTRL_RES_SIZE, "gcb_sio"),
133f3e89362SColin Foster };
134f3e89362SColin Foster 
135*c21ff093SColin Foster static const struct resource vsc7512_serdes_resources[] = {
136*c21ff093SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_HSIO_RES_START, VSC7512_HSIO_RES_SIZE, "hsio"),
137*c21ff093SColin Foster };
138*c21ff093SColin Foster 
1398dccdd27SColin Foster static const struct resource vsc7512_switch_resources[] = {
1408dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_ANA_RES_START, VSC7512_ANA_RES_SIZE, "ana"),
141*c21ff093SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_HSIO_RES_START, VSC7512_HSIO_RES_SIZE, "hsio"),
1428dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_QS_RES_START, VSC7512_QS_RES_SIZE, "qs"),
1438dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_QSYS_RES_START, VSC7512_QSYS_RES_SIZE, "qsys"),
1448dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_REW_RES_START, VSC7512_REW_RES_SIZE, "rew"),
1458dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_SYS_RES_START, VSC7512_SYS_RES_SIZE, "sys"),
1468dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_S0_RES_START, VCAP_RES_SIZE, "s0"),
1478dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_S1_RES_START, VCAP_RES_SIZE, "s1"),
1488dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_S2_RES_START, VCAP_RES_SIZE, "s2"),
1498dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_0_RES_START, VSC7512_PORT_RES_SIZE, "port0"),
1508dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_1_RES_START, VSC7512_PORT_RES_SIZE, "port1"),
1518dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_2_RES_START, VSC7512_PORT_RES_SIZE, "port2"),
1528dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_3_RES_START, VSC7512_PORT_RES_SIZE, "port3"),
1538dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_4_RES_START, VSC7512_PORT_RES_SIZE, "port4"),
1548dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_5_RES_START, VSC7512_PORT_RES_SIZE, "port5"),
1558dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_6_RES_START, VSC7512_PORT_RES_SIZE, "port6"),
1568dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_7_RES_START, VSC7512_PORT_RES_SIZE, "port7"),
1578dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_8_RES_START, VSC7512_PORT_RES_SIZE, "port8"),
1588dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_9_RES_START, VSC7512_PORT_RES_SIZE, "port9"),
1598dccdd27SColin Foster 	DEFINE_RES_REG_NAMED(VSC7512_PORT_10_RES_START, VSC7512_PORT_RES_SIZE, "port10")
1608dccdd27SColin Foster };
1618dccdd27SColin Foster 
162f3e89362SColin Foster static const struct mfd_cell vsc7512_devs[] = {
163f3e89362SColin Foster 	{
164f3e89362SColin Foster 		.name = "ocelot-pinctrl",
165f3e89362SColin Foster 		.of_compatible = "mscc,ocelot-pinctrl",
166f3e89362SColin Foster 		.num_resources = ARRAY_SIZE(vsc7512_pinctrl_resources),
167f3e89362SColin Foster 		.resources = vsc7512_pinctrl_resources,
168f3e89362SColin Foster 	}, {
169f3e89362SColin Foster 		.name = "ocelot-sgpio",
170f3e89362SColin Foster 		.of_compatible = "mscc,ocelot-sgpio",
171f3e89362SColin Foster 		.num_resources = ARRAY_SIZE(vsc7512_sgpio_resources),
172f3e89362SColin Foster 		.resources = vsc7512_sgpio_resources,
173f3e89362SColin Foster 	}, {
174f3e89362SColin Foster 		.name = "ocelot-miim0",
175f3e89362SColin Foster 		.of_compatible = "mscc,ocelot-miim",
176f3e89362SColin Foster 		.of_reg = VSC7512_MIIM0_RES_START,
177f3e89362SColin Foster 		.use_of_reg = true,
178f3e89362SColin Foster 		.num_resources = ARRAY_SIZE(vsc7512_miim0_resources),
179f3e89362SColin Foster 		.resources = vsc7512_miim0_resources,
180f3e89362SColin Foster 	}, {
181f3e89362SColin Foster 		.name = "ocelot-miim1",
182f3e89362SColin Foster 		.of_compatible = "mscc,ocelot-miim",
183f3e89362SColin Foster 		.of_reg = VSC7512_MIIM1_RES_START,
184f3e89362SColin Foster 		.use_of_reg = true,
185f3e89362SColin Foster 		.num_resources = ARRAY_SIZE(vsc7512_miim1_resources),
186f3e89362SColin Foster 		.resources = vsc7512_miim1_resources,
1878dccdd27SColin Foster 	}, {
188*c21ff093SColin Foster 		.name = "ocelot-serdes",
189*c21ff093SColin Foster 		.of_compatible = "mscc,vsc7514-serdes",
190*c21ff093SColin Foster 		.num_resources = ARRAY_SIZE(vsc7512_serdes_resources),
191*c21ff093SColin Foster 		.resources = vsc7512_serdes_resources,
192*c21ff093SColin Foster 	}, {
193ef1a99c6SVladimir Oltean 		.name = "ocelot-ext-switch",
1948dccdd27SColin Foster 		.of_compatible = "mscc,vsc7512-switch",
1958dccdd27SColin Foster 		.num_resources = ARRAY_SIZE(vsc7512_switch_resources),
1968dccdd27SColin Foster 		.resources = vsc7512_switch_resources,
197f3e89362SColin Foster 	},
198f3e89362SColin Foster };
199f3e89362SColin Foster 
ocelot_core_try_add_regmap(struct device * dev,const struct resource * res)200f3e89362SColin Foster static void ocelot_core_try_add_regmap(struct device *dev,
201f3e89362SColin Foster 				       const struct resource *res)
202f3e89362SColin Foster {
203f3e89362SColin Foster 	if (dev_get_regmap(dev, res->name))
204f3e89362SColin Foster 		return;
205f3e89362SColin Foster 
206f3e89362SColin Foster 	ocelot_spi_init_regmap(dev, res);
207f3e89362SColin Foster }
208f3e89362SColin Foster 
ocelot_core_try_add_regmaps(struct device * dev,const struct mfd_cell * cell)209f3e89362SColin Foster static void ocelot_core_try_add_regmaps(struct device *dev,
210f3e89362SColin Foster 					const struct mfd_cell *cell)
211f3e89362SColin Foster {
212f3e89362SColin Foster 	int i;
213f3e89362SColin Foster 
214f3e89362SColin Foster 	for (i = 0; i < cell->num_resources; i++)
215f3e89362SColin Foster 		ocelot_core_try_add_regmap(dev, &cell->resources[i]);
216f3e89362SColin Foster }
217f3e89362SColin Foster 
ocelot_core_init(struct device * dev)218f3e89362SColin Foster int ocelot_core_init(struct device *dev)
219f3e89362SColin Foster {
220f3e89362SColin Foster 	int i, ndevs;
221f3e89362SColin Foster 
222f3e89362SColin Foster 	ndevs = ARRAY_SIZE(vsc7512_devs);
223f3e89362SColin Foster 
224f3e89362SColin Foster 	for (i = 0; i < ndevs; i++)
225f3e89362SColin Foster 		ocelot_core_try_add_regmaps(dev, &vsc7512_devs[i]);
226f3e89362SColin Foster 
227f3e89362SColin Foster 	return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL);
228f3e89362SColin Foster }
229f3e89362SColin Foster EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT);
230f3e89362SColin Foster 
231f3e89362SColin Foster MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver");
232f3e89362SColin Foster MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>");
233f3e89362SColin Foster MODULE_LICENSE("GPL");
234f3e89362SColin Foster MODULE_IMPORT_NS(MFD_OCELOT_SPI);
235