chipc.c revision 298278
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: head/sys/dev/bhnd/cores/chipc/chipc.c 298278 2016-04-19 15:56:39Z adrian $");
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
58devclass_t bhnd_chipc_devclass;	/**< bhnd(4) chipcommon device class */
59
60static const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = {
61	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
62	{ -1, -1, 0 }
63};
64
65static struct bhnd_device_quirk chipc_quirks[];
66
67/* Supported device identifiers */
68static const struct bhnd_device chipc_devices[] = {
69	BHND_DEVICE(CC, "", chipc_quirks),
70	BHND_DEVICE_END
71};
72
73
74/* Device quirks table */
75static struct bhnd_device_quirk chipc_quirks[] = {
76	{ BHND_HWREV_RANGE	(0,	21),	CHIPC_QUIRK_ALWAYS_HAS_SPROM },
77	{ BHND_HWREV_EQ		(22),		CHIPC_QUIRK_SPROM_CHECK_CST_R22 },
78	{ BHND_HWREV_RANGE	(23,	31),	CHIPC_QUIRK_SPROM_CHECK_CST_R23 },
79	{ BHND_HWREV_GTE	(35),		CHIPC_QUIRK_SUPPORTS_NFLASH },
80	BHND_DEVICE_QUIRK_END
81};
82
83/* quirk and capability flag convenience macros */
84#define	CHIPC_QUIRK(_sc, _name)	\
85    ((_sc)->quirks & CHIPC_QUIRK_ ## _name)
86
87#define CHIPC_CAP(_sc, _name)	\
88    ((_sc)->caps & CHIPC_ ## _name)
89
90#define	CHIPC_ASSERT_QUIRK(_sc, name)	\
91    KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
92
93#define	CHIPC_ASSERT_CAP(_sc, name)	\
94    KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set"))
95
96static int
97chipc_probe(device_t dev)
98{
99	const struct bhnd_device *id;
100
101	id = bhnd_device_lookup(dev, chipc_devices, sizeof(chipc_devices[0]));
102	if (id == NULL)
103		return (ENXIO);
104
105	bhnd_set_default_core_desc(dev);
106	return (BUS_PROBE_DEFAULT);
107}
108
109static int
110chipc_attach(device_t dev)
111{
112	struct chipc_softc		*sc;
113	bhnd_addr_t			 enum_addr;
114	uint32_t			 ccid_reg;
115	uint8_t				 chip_type;
116	int				 error;
117
118	sc = device_get_softc(dev);
119	sc->dev = dev;
120	sc->quirks = bhnd_device_quirks(dev, chipc_devices,
121	    sizeof(chipc_devices[0]));
122
123	/* Allocate bus resources */
124	memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec));
125	if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
126		return (error);
127
128	sc->core = sc->res[0];
129
130	/* Fetch our chipset identification data */
131	ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID);
132	chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS);
133
134	switch (chip_type) {
135	case BHND_CHIPTYPE_SIBA:
136		/* enumeration space starts at the ChipCommon register base. */
137		enum_addr = rman_get_start(sc->core->res);
138		break;
139	case BHND_CHIPTYPE_BCMA:
140	case BHND_CHIPTYPE_BCMA_ALT:
141		enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR);
142		break;
143	default:
144		device_printf(dev, "unsupported chip type %hhu\n", chip_type);
145		error = ENODEV;
146		goto cleanup;
147	}
148
149	sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr);
150
151	/* Fetch capability and status register values */
152	sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
153	sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
154
155	// TODO
156	switch (bhnd_chipc_nvram_src(dev)) {
157	case BHND_NVRAM_SRC_CIS:
158		device_printf(dev, "NVRAM source: CIS\n");
159		break;
160	case BHND_NVRAM_SRC_SPROM:
161		device_printf(dev, "NVRAM source: SPROM\n");
162		break;
163	case BHND_NVRAM_SRC_OTP:
164		device_printf(dev, "NVRAM source: OTP\n");
165		break;
166	case BHND_NVRAM_SRC_NFLASH:
167		device_printf(dev, "NVRAM source: NFLASH\n");
168		break;
169	case BHND_NVRAM_SRC_NONE:
170		device_printf(dev, "NVRAM source: NONE\n");
171		break;
172	}
173
174	return (0);
175
176cleanup:
177	bhnd_release_resources(dev, sc->rspec, sc->res);
178	return (error);
179}
180
181static int
182chipc_detach(device_t dev)
183{
184	struct chipc_softc	*sc;
185
186	sc = device_get_softc(dev);
187	bhnd_release_resources(dev, sc->rspec, sc->res);
188
189	return (0);
190}
191
192static int
193chipc_suspend(device_t dev)
194{
195	return (0);
196}
197
198static int
199chipc_resume(device_t dev)
200{
201	return (0);
202}
203
204/**
205 * Use device-specific ChipStatus flags to determine the preferred NVRAM
206 * data source.
207 */
208static bhnd_nvram_src_t
209chipc_nvram_src_chipst(struct chipc_softc *sc)
210{
211	uint8_t		nvram_sel;
212
213	CHIPC_ASSERT_QUIRK(sc, SPROM_CHECK_CHIPST);
214
215	if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R22)) {
216		// TODO: On these devices, the official driver code always
217		// assumes SPROM availability if CHIPC_CST_OTP_SEL is not
218		// set; we must review against the actual behavior of our
219		// BCM4312 hardware
220		nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R22);
221	} else if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R23)) {
222		nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R23);
223	} else {
224		panic("invalid CST OTP/SPROM chipc quirk flags");
225	}
226	device_printf(sc->dev, "querying chipst for 0x%x, 0x%x\n", sc->ccid.chip_id, sc->cst);
227
228	switch (nvram_sel) {
229	case CHIPC_CST_DEFCIS_SEL:
230		return (BHND_NVRAM_SRC_CIS);
231
232	case CHIPC_CST_SPROM_SEL:
233	case CHIPC_CST_OTP_PWRDN:
234		return (BHND_NVRAM_SRC_SPROM);
235
236	case CHIPC_CST_OTP_SEL:
237		return (BHND_NVRAM_SRC_OTP);
238
239	default:
240		device_printf(sc->dev, "unrecognized OTP/SPROM type 0x%hhx",
241		    nvram_sel);
242		return (BHND_NVRAM_SRC_NONE);
243	}
244}
245
246/**
247 * Determine the preferred NVRAM data source.
248 */
249static bhnd_nvram_src_t
250chipc_nvram_src(device_t dev)
251{
252	struct chipc_softc	*sc;
253	uint32_t		 srom_ctrl;
254
255	sc = device_get_softc(dev);
256
257	/* Very early devices always included a SPROM */
258	if (CHIPC_QUIRK(sc, ALWAYS_HAS_SPROM))
259		return (BHND_NVRAM_SRC_SPROM);
260
261	/* Most other early devices require checking ChipStatus flags */
262	if (CHIPC_QUIRK(sc, SPROM_CHECK_CHIPST))
263		return (chipc_nvram_src_chipst(sc));
264
265	/*
266	 * Later chipset revisions standardized the NVRAM capability flags and
267	 * register interfaces.
268	 *
269	 * We check for hardware presence in order of precedence. For example,
270	 * SPROM is is always used in preference to internal OTP if found.
271	 */
272	if (CHIPC_CAP(sc, CAP_SPROM)) {
273		srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL);
274		if (srom_ctrl & CHIPC_SRC_PRESENT)
275			return (BHND_NVRAM_SRC_SPROM);
276	}
277
278	/* Check for OTP */
279	if (CHIPC_CAP(sc, CAP_OTP_SIZE))
280		return (BHND_NVRAM_SRC_OTP);
281
282	/*
283	 * Finally, Northstar chipsets (and possibly other chipsets?) support
284	 * external NAND flash.
285	 */
286	if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH))
287		return (BHND_NVRAM_SRC_NFLASH);
288
289	/* No NVRAM hardware capability declared */
290	return (BHND_NVRAM_SRC_NONE);
291}
292
293static device_method_t chipc_methods[] = {
294	/* Device interface */
295	DEVMETHOD(device_probe,		chipc_probe),
296	DEVMETHOD(device_attach,	chipc_attach),
297	DEVMETHOD(device_detach,	chipc_detach),
298	DEVMETHOD(device_suspend,	chipc_suspend),
299	DEVMETHOD(device_resume,	chipc_resume),
300
301	/* ChipCommon interface */
302	DEVMETHOD(bhnd_chipc_nvram_src,	chipc_nvram_src),
303
304	DEVMETHOD_END
305};
306
307DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
308DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0);
309MODULE_VERSION(bhnd_chipc, 1);
310