xref: /freebsd/sys/dev/bhnd/cores/chipc/chipc.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
1 /*-
2  * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 /*
34  * Broadcom ChipCommon driver.
35  *
36  * With the exception of some very early chipsets, the ChipCommon core
37  * has been included in all HND SoCs and chipsets based on the siba(4)
38  * and bcma(4) interconnects, providing a common interface to chipset
39  * identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO,
40  * flash, etc.
41  */
42 
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/bus.h>
46 #include <sys/module.h>
47 #include <sys/systm.h>
48 
49 #include <machine/bus.h>
50 #include <sys/rman.h>
51 #include <machine/resource.h>
52 
53 #include <dev/bhnd/bhnd.h>
54 
55 #include "chipcreg.h"
56 #include "chipcvar.h"
57 
58 devclass_t bhnd_chipc_devclass;	/**< bhnd(4) chipcommon device class */
59 
60 static const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = {
61 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
62 	{ -1, -1, 0 }
63 };
64 
65 /* Supported device identifiers */
66 static const struct chipc_device {
67 	uint16_t	 device;
68 } chipc_devices[] = {
69 	{ BHND_COREID_CC },
70 	{ BHND_COREID_INVALID }
71 };
72 
73 /* Device quirks table */
74 static struct bhnd_device_quirk chipc_quirks[] = {
75 	BHND_QUIRK_HWREV_RANGE	(0,	21,	CHIPC_QUIRK_ALWAYS_HAS_SPROM),
76 	BHND_QUIRK_HWREV_EQ	(22,		CHIPC_QUIRK_SPROM_CHECK_CST_R22),
77 	BHND_QUIRK_HWREV_RANGE	(23,	31,	CHIPC_QUIRK_SPROM_CHECK_CST_R23),
78 	BHND_QUIRK_HWREV_GTE	(35,		CHIPC_QUIRK_SUPPORTS_NFLASH),
79 	BHND_QUIRK_HWREV_END
80 };
81 
82 /* quirk and capability flag convenience macros */
83 #define	CHIPC_QUIRK(_sc, _name)	\
84     ((_sc)->quirks & CHIPC_QUIRK_ ## _name)
85 
86 #define CHIPC_CAP(_sc, _name)	\
87     ((_sc)->caps & CHIPC_ ## _name)
88 
89 #define	CHIPC_ASSERT_QUIRK(_sc, name)	\
90     KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
91 
92 #define	CHIPC_ASSERT_CAP(_sc, name)	\
93     KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set"))
94 
95 static int
96 chipc_probe(device_t dev)
97 {
98 	const struct chipc_device	*id;
99 
100 	for (id = chipc_devices; id->device != BHND_COREID_INVALID; id++)
101 	{
102 		if (bhnd_get_vendor(dev) == BHND_MFGID_BCM &&
103 		    bhnd_get_device(dev) == id->device)
104 		{
105 			bhnd_set_generic_core_desc(dev);
106 			return (BUS_PROBE_DEFAULT);
107 		}
108 	}
109 
110 	return (ENXIO);
111 }
112 
113 static int
114 chipc_attach(device_t dev)
115 {
116 	struct bhnd_device_quirk	*dq;
117 	struct chipc_softc		*sc;
118 	bhnd_addr_t			 enum_addr;
119 	uint32_t			 ccid_reg;
120 	uint8_t				 chip_type;
121 	int				 error;
122 
123 	sc = device_get_softc(dev);
124 	sc->dev = dev;
125 
126 	/* Allocate bus resources */
127 	memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec));
128 	if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
129 		return (error);
130 
131 	sc->core = sc->res[0];
132 
133 	/* Fetch our chipset identification data */
134 	ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID);
135 	chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS);
136 
137 	switch (chip_type) {
138 	case BHND_CHIPTYPE_SIBA:
139 		/* enumeration space starts at the ChipCommon register base. */
140 		enum_addr = rman_get_start(sc->core->res);
141 		break;
142 	case BHND_CHIPTYPE_BCMA:
143 	case BHND_CHIPTYPE_BCMA_ALT:
144 		enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR);
145 		break;
146 	default:
147 		device_printf(dev, "unsupported chip type %hhu\n", chip_type);
148 		error = ENODEV;
149 		goto cleanup;
150 	}
151 
152 	sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr);
153 
154 	/* Fetch capability and status register values */
155 	sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
156 	sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
157 
158 	/* Populate the set of applicable quirk flags */
159 	sc->quirks = 0;
160 	for (dq = chipc_quirks; dq->quirks != 0; dq++) {
161 		if (bhnd_hwrev_matches(bhnd_get_hwrev(dev), &dq->hwrev))
162 			sc->quirks |= dq->quirks;
163 	};
164 
165 	// TODO
166 	switch (bhnd_chipc_nvram_src(dev)) {
167 	case BHND_NVRAM_SRC_CIS:
168 		device_printf(dev, "NVRAM source: CIS\n");
169 		break;
170 	case BHND_NVRAM_SRC_SPROM:
171 		device_printf(dev, "NVRAM source: SPROM\n");
172 		break;
173 	case BHND_NVRAM_SRC_OTP:
174 		device_printf(dev, "NVRAM source: OTP\n");
175 		break;
176 	case BHND_NVRAM_SRC_NFLASH:
177 		device_printf(dev, "NVRAM source: NFLASH\n");
178 		break;
179 	case BHND_NVRAM_SRC_NONE:
180 		device_printf(dev, "NVRAM source: NONE\n");
181 		break;
182 	}
183 
184 	return (0);
185 
186 cleanup:
187 	bhnd_release_resources(dev, sc->rspec, sc->res);
188 	return (error);
189 }
190 
191 static int
192 chipc_detach(device_t dev)
193 {
194 	struct chipc_softc	*sc;
195 
196 	sc = device_get_softc(dev);
197 	bhnd_release_resources(dev, sc->rspec, sc->res);
198 
199 	return (0);
200 }
201 
202 static int
203 chipc_suspend(device_t dev)
204 {
205 	return (0);
206 }
207 
208 static int
209 chipc_resume(device_t dev)
210 {
211 	return (0);
212 }
213 
214 /**
215  * Use device-specific ChipStatus flags to determine the preferred NVRAM
216  * data source.
217  */
218 static bhnd_nvram_src_t
219 chipc_nvram_src_chipst(struct chipc_softc *sc)
220 {
221 	uint8_t		nvram_sel;
222 
223 	CHIPC_ASSERT_QUIRK(sc, SPROM_CHECK_CHIPST);
224 
225 	if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R22)) {
226 		// TODO: On these devices, the official driver code always
227 		// assumes SPROM availability if CHIPC_CST_OTP_SEL is not
228 		// set; we must review against the actual behavior of our
229 		// BCM4312 hardware
230 		nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R22);
231 	} else if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R23)) {
232 		nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R23);
233 	} else {
234 		panic("invalid CST OTP/SPROM chipc quirk flags");
235 	}
236 	device_printf(sc->dev, "querying chipst for 0x%x, 0x%x\n", sc->ccid.chip_id, sc->cst);
237 
238 	switch (nvram_sel) {
239 	case CHIPC_CST_DEFCIS_SEL:
240 		return (BHND_NVRAM_SRC_CIS);
241 
242 	case CHIPC_CST_SPROM_SEL:
243 	case CHIPC_CST_OTP_PWRDN:
244 		return (BHND_NVRAM_SRC_SPROM);
245 
246 	case CHIPC_CST_OTP_SEL:
247 		return (BHND_NVRAM_SRC_OTP);
248 
249 	default:
250 		device_printf(sc->dev, "unrecognized OTP/SPROM type 0x%hhx",
251 		    nvram_sel);
252 		return (BHND_NVRAM_SRC_NONE);
253 	}
254 }
255 
256 /**
257  * Determine the preferred NVRAM data source.
258  */
259 static bhnd_nvram_src_t
260 chipc_nvram_src(device_t dev)
261 {
262 	struct chipc_softc	*sc;
263 	uint32_t		 srom_ctrl;
264 
265 	sc = device_get_softc(dev);
266 
267 	/* Very early devices always included a SPROM */
268 	if (CHIPC_QUIRK(sc, ALWAYS_HAS_SPROM))
269 		return (BHND_NVRAM_SRC_SPROM);
270 
271 	/* Most other early devices require checking ChipStatus flags */
272 	if (CHIPC_QUIRK(sc, SPROM_CHECK_CHIPST))
273 		return (chipc_nvram_src_chipst(sc));
274 
275 	/*
276 	 * Later chipset revisions standardized the NVRAM capability flags and
277 	 * register interfaces.
278 	 *
279 	 * We check for hardware presence in order of precedence. For example,
280 	 * SPROM is is always used in preference to internal OTP if found.
281 	 */
282 	if (CHIPC_CAP(sc, CAP_SPROM)) {
283 		srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL);
284 		if (srom_ctrl & CHIPC_SRC_PRESENT)
285 			return (BHND_NVRAM_SRC_SPROM);
286 	}
287 
288 	/* Check for OTP */
289 	if (CHIPC_CAP(sc, CAP_OTP_SIZE))
290 		return (BHND_NVRAM_SRC_OTP);
291 
292 	/*
293 	 * Finally, Northstar chipsets (and possibly other chipsets?) support
294 	 * external NAND flash.
295 	 */
296 	if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH))
297 		return (BHND_NVRAM_SRC_NFLASH);
298 
299 	/* No NVRAM hardware capability declared */
300 	return (BHND_NVRAM_SRC_NONE);
301 }
302 
303 static device_method_t chipc_methods[] = {
304 	/* Device interface */
305 	DEVMETHOD(device_probe,		chipc_probe),
306 	DEVMETHOD(device_attach,	chipc_attach),
307 	DEVMETHOD(device_detach,	chipc_detach),
308 	DEVMETHOD(device_suspend,	chipc_suspend),
309 	DEVMETHOD(device_resume,	chipc_resume),
310 
311 	/* ChipCommon interface */
312 	DEVMETHOD(bhnd_chipc_nvram_src,	chipc_nvram_src),
313 
314 	DEVMETHOD_END
315 };
316 
317 DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
318 DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0);
319 MODULE_VERSION(bhnd_chipc, 1);
320