chipc.c revision 299241
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 299241 2016-05-08 19:14:05Z 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 "bhnd_nvram_if.h"
56
57#include "chipcreg.h"
58#include "chipcvar.h"
59
60devclass_t bhnd_chipc_devclass;	/**< bhnd(4) chipcommon device class */
61
62static const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = {
63	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
64	{ -1, -1, 0 }
65};
66
67static struct bhnd_device_quirk chipc_quirks[];
68
69/* Supported device identifiers */
70static const struct bhnd_device chipc_devices[] = {
71	BHND_DEVICE(CC, "CC", chipc_quirks),
72	BHND_DEVICE_END
73};
74
75
76/* Device quirks table */
77static struct bhnd_device_quirk chipc_quirks[] = {
78	{ BHND_HWREV_GTE	(32),	CHIPC_QUIRK_SUPPORTS_SPROM },
79	{ BHND_HWREV_GTE	(35),	CHIPC_QUIRK_SUPPORTS_NFLASH },
80	BHND_DEVICE_QUIRK_END
81};
82
83/* Chip-specific quirks table */
84static struct bhnd_chip_quirk chipc_chip_quirks[] = {
85	/* 4331 12x9 packages */
86	{{ BHND_CHIP_IP(4331, 4331TN) },
87		CHIPC_QUIRK_4331_GPIO2_5_MUX_SPROM
88	},
89	{{ BHND_CHIP_IP(4331, 4331TNA0) },
90		CHIPC_QUIRK_4331_GPIO2_5_MUX_SPROM
91	},
92
93	/* 4331 12x12 packages */
94	{{ BHND_CHIP_IPR(4331, 4331TT, HWREV_GTE(1)) },
95		CHIPC_QUIRK_4331_EXTPA2_MUX_SPROM
96	},
97
98	/* 4331 (all packages/revisions) */
99	{{ BHND_CHIP_ID(4331) },
100		CHIPC_QUIRK_4331_EXTPA_MUX_SPROM
101	},
102
103	/* 4360 family (all revs <= 2) */
104	{{ BHND_CHIP_IR(4352, HWREV_LTE(2)) },
105		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
106	{{ BHND_CHIP_IR(43460, HWREV_LTE(2)) },
107		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
108	{{ BHND_CHIP_IR(43462, HWREV_LTE(2)) },
109		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
110	{{ BHND_CHIP_IR(43602, HWREV_LTE(2)) },
111		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
112
113	BHND_CHIP_QUIRK_END
114};
115
116/* quirk and capability flag convenience macros */
117#define	CHIPC_QUIRK(_sc, _name)	\
118    ((_sc)->quirks & CHIPC_QUIRK_ ## _name)
119
120#define CHIPC_CAP(_sc, _name)	\
121    ((_sc)->caps & CHIPC_ ## _name)
122
123#define	CHIPC_ASSERT_QUIRK(_sc, name)	\
124    KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
125
126#define	CHIPC_ASSERT_CAP(_sc, name)	\
127    KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set"))
128
129static bhnd_nvram_src_t	chipc_nvram_identify(struct chipc_softc *sc);
130static int		chipc_sprom_init(struct chipc_softc *);
131static int		chipc_enable_sprom_pins(struct chipc_softc *);
132static int		chipc_disable_sprom_pins(struct chipc_softc *);
133
134
135static int
136chipc_probe(device_t dev)
137{
138	const struct bhnd_device *id;
139
140	id = bhnd_device_lookup(dev, chipc_devices, sizeof(chipc_devices[0]));
141	if (id == NULL)
142		return (ENXIO);
143
144	bhnd_set_default_core_desc(dev);
145	return (BUS_PROBE_DEFAULT);
146}
147
148static int
149chipc_attach(device_t dev)
150{
151	struct chipc_softc		*sc;
152	bhnd_addr_t			 enum_addr;
153	uint32_t			 ccid_reg;
154	uint8_t				 chip_type;
155	int				 error;
156
157	sc = device_get_softc(dev);
158	sc->dev = dev;
159	sc->quirks = bhnd_device_quirks(dev, chipc_devices,
160	    sizeof(chipc_devices[0]));
161	sc->quirks |= bhnd_chip_quirks(dev, chipc_chip_quirks);
162
163	CHIPC_LOCK_INIT(sc);
164
165	/* Allocate bus resources */
166	memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec));
167	if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
168		return (error);
169
170	sc->core = sc->res[0];
171
172	/* Fetch our chipset identification data */
173	ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID);
174	chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS);
175
176	switch (chip_type) {
177	case BHND_CHIPTYPE_SIBA:
178		/* enumeration space starts at the ChipCommon register base. */
179		enum_addr = rman_get_start(sc->core->res);
180		break;
181	case BHND_CHIPTYPE_BCMA:
182	case BHND_CHIPTYPE_BCMA_ALT:
183		enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR);
184		break;
185	default:
186		device_printf(dev, "unsupported chip type %hhu\n", chip_type);
187		error = ENODEV;
188		goto cleanup;
189	}
190
191	sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr);
192
193	/* Fetch capability and status register values */
194	sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
195	sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
196
197	/* Identify NVRAM source */
198	sc->nvram_src = chipc_nvram_identify(sc);
199
200	/* Read NVRAM data */
201	switch (sc->nvram_src) {
202	case BHND_NVRAM_SRC_OTP:
203		// TODO (requires access to OTP hardware)
204		device_printf(sc->dev, "NVRAM-OTP unsupported\n");
205		break;
206
207	case BHND_NVRAM_SRC_NFLASH:
208		// TODO (requires access to NFLASH hardware)
209		device_printf(sc->dev, "NVRAM-NFLASH unsupported\n");
210		break;
211
212	case BHND_NVRAM_SRC_SPROM:
213		if ((error = chipc_sprom_init(sc)))
214			goto cleanup;
215		break;
216
217	case BHND_NVRAM_SRC_UNKNOWN:
218		/* Handled externally */
219		break;
220	}
221
222	return (0);
223
224cleanup:
225	bhnd_release_resources(dev, sc->rspec, sc->res);
226	CHIPC_LOCK_DESTROY(sc);
227	return (error);
228}
229
230static int
231chipc_detach(device_t dev)
232{
233	struct chipc_softc	*sc;
234
235	sc = device_get_softc(dev);
236	bhnd_release_resources(dev, sc->rspec, sc->res);
237	bhnd_sprom_fini(&sc->sprom);
238
239	CHIPC_LOCK_DESTROY(sc);
240
241	return (0);
242}
243
244static int
245chipc_suspend(device_t dev)
246{
247	return (0);
248}
249
250static int
251chipc_resume(device_t dev)
252{
253	return (0);
254}
255
256/**
257 * Initialize local SPROM shadow, if required.
258 *
259 * @param sc chipc driver state.
260 */
261static int
262chipc_sprom_init(struct chipc_softc *sc)
263{
264	int	error;
265
266	KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM,
267	    ("non-SPROM source (%u)\n", sc->nvram_src));
268
269	/* Enable access to the SPROM */
270	CHIPC_LOCK(sc);
271	if ((error = chipc_enable_sprom_pins(sc)))
272		goto failed;
273
274	/* Initialize SPROM parser */
275	error = bhnd_sprom_init(&sc->sprom, sc->core, CHIPC_SPROM_OTP);
276	if (error) {
277		device_printf(sc->dev, "SPROM identification failed: %d\n",
278			error);
279
280		chipc_disable_sprom_pins(sc);
281		goto failed;
282	}
283
284	/* Drop access to the SPROM lines */
285	if ((error = chipc_disable_sprom_pins(sc))) {
286		bhnd_sprom_fini(&sc->sprom);
287		goto failed;
288	}
289	CHIPC_UNLOCK(sc);
290
291	return (0);
292
293failed:
294	CHIPC_UNLOCK(sc);
295	return (error);
296}
297
298/**
299 * Determine the NVRAM data source for this device.
300 *
301 * @param sc chipc driver state.
302 */
303static bhnd_nvram_src_t
304chipc_nvram_identify(struct chipc_softc *sc)
305{
306	uint32_t		 srom_ctrl;
307
308	/* Very early devices vend SPROM/OTP/CIS (if at all) via the
309	 * host bridge interface instead of ChipCommon. */
310	if (!CHIPC_QUIRK(sc, SUPPORTS_SPROM))
311		return (BHND_NVRAM_SRC_UNKNOWN);
312
313	/*
314	 * Later chipset revisions standardized the SPROM capability flags and
315	 * register interfaces.
316	 *
317	 * We check for hardware presence in order of precedence. For example,
318	 * SPROM is is always used in preference to internal OTP if found.
319	 */
320	if (CHIPC_CAP(sc, CAP_SPROM)) {
321		srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL);
322		if (srom_ctrl & CHIPC_SRC_PRESENT)
323			return (BHND_NVRAM_SRC_SPROM);
324	}
325
326	/* Check for OTP */
327	if (CHIPC_CAP(sc, CAP_OTP_SIZE))
328		return (BHND_NVRAM_SRC_OTP);
329
330	/*
331	 * Finally, Northstar chipsets (and possibly other chipsets?) support
332	 * external NAND flash.
333	 */
334	if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH))
335		return (BHND_NVRAM_SRC_NFLASH);
336
337	/* No NVRAM hardware capability declared */
338	return (BHND_NVRAM_SRC_UNKNOWN);
339}
340
341
342/**
343 * If required by this device, enable access to the SPROM.
344 *
345 * @param sc chipc driver state.
346 */
347static int
348chipc_enable_sprom_pins(struct chipc_softc *sc)
349{
350	uint32_t cctrl;
351
352	CHIPC_LOCK_ASSERT(sc, MA_OWNED);
353
354	/* Nothing to do? */
355	if (!CHIPC_QUIRK(sc, MUX_SPROM))
356		return (0);
357
358	cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
359
360	/* 4331 devices */
361	if (CHIPC_QUIRK(sc, 4331_EXTPA_MUX_SPROM)) {
362		cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN;
363
364		if (CHIPC_QUIRK(sc, 4331_GPIO2_5_MUX_SPROM))
365			cctrl &= ~CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5;
366
367		if (CHIPC_QUIRK(sc, 4331_EXTPA2_MUX_SPROM))
368			cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN2;
369
370		bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
371		return (0);
372	}
373
374	/* 4360 devices */
375	if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
376		/* Unimplemented */
377	}
378
379	/* Refuse to proceed on unsupported devices with muxed SPROM pins */
380	device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
381	return (ENXIO);
382}
383
384/**
385 * If required by this device, revert any GPIO/pin configuration applied
386 * to allow SPROM access.
387 *
388 * @param sc chipc driver state.
389 */
390static int
391chipc_disable_sprom_pins(struct chipc_softc *sc)
392{
393	uint32_t cctrl;
394
395	CHIPC_LOCK_ASSERT(sc, MA_OWNED);
396
397	/* Nothing to do? */
398	if (!CHIPC_QUIRK(sc, MUX_SPROM))
399		return (0);
400
401	cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
402
403	/* 4331 devices */
404	if (CHIPC_QUIRK(sc, 4331_EXTPA_MUX_SPROM)) {
405		cctrl |= CHIPC_CCTRL4331_EXTPA_EN;
406
407		if (CHIPC_QUIRK(sc, 4331_GPIO2_5_MUX_SPROM))
408			cctrl |= CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5;
409
410		if (CHIPC_QUIRK(sc, 4331_EXTPA2_MUX_SPROM))
411			cctrl |= CHIPC_CCTRL4331_EXTPA_EN2;
412
413		bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
414		return (0);
415	}
416
417	/* 4360 devices */
418	if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
419		/* Unimplemented */
420	}
421
422	/* Refuse to proceed on unsupported devices with muxed SPROM pins */
423	device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
424	return (ENXIO);
425}
426
427static bhnd_nvram_src_t
428chipc_nvram_src(device_t dev)
429{
430	struct chipc_softc *sc = device_get_softc(dev);
431	return (sc->nvram_src);
432}
433
434static int
435chipc_nvram_getvar(device_t dev, const char *name, void *buf, size_t *len)
436{
437	struct chipc_softc	*sc;
438	int			 error;
439
440	sc = device_get_softc(dev);
441
442	switch (sc->nvram_src) {
443	case BHND_NVRAM_SRC_SPROM:
444		CHIPC_LOCK(sc);
445		error = bhnd_sprom_getvar(&sc->sprom, name, buf, len);
446		CHIPC_UNLOCK(sc);
447		return (error);
448
449	case BHND_NVRAM_SRC_OTP:
450	case BHND_NVRAM_SRC_NFLASH:
451		/* Currently unsupported */
452		return (ENXIO);
453
454	case BHND_NVRAM_SRC_UNKNOWN:
455		return (ENODEV);
456	}
457
458	/* Unknown NVRAM source */
459	return (ENODEV);
460}
461
462static int
463chipc_nvram_setvar(device_t dev, const char *name, const void *buf,
464    size_t len)
465{
466	struct chipc_softc	*sc;
467	int			 error;
468
469	sc = device_get_softc(dev);
470
471	switch (sc->nvram_src) {
472	case BHND_NVRAM_SRC_SPROM:
473		CHIPC_LOCK(sc);
474		error = bhnd_sprom_setvar(&sc->sprom, name, buf, len);
475		CHIPC_UNLOCK(sc);
476		return (error);
477
478	case BHND_NVRAM_SRC_OTP:
479	case BHND_NVRAM_SRC_NFLASH:
480		/* Currently unsupported */
481		return (ENXIO);
482
483	case BHND_NVRAM_SRC_UNKNOWN:
484	default:
485		return (ENODEV);
486	}
487
488	/* Unknown NVRAM source */
489	return (ENODEV);
490}
491
492static device_method_t chipc_methods[] = {
493	/* Device interface */
494	DEVMETHOD(device_probe,		chipc_probe),
495	DEVMETHOD(device_attach,	chipc_attach),
496	DEVMETHOD(device_detach,	chipc_detach),
497	DEVMETHOD(device_suspend,	chipc_suspend),
498	DEVMETHOD(device_resume,	chipc_resume),
499
500	/* ChipCommon interface */
501	DEVMETHOD(bhnd_chipc_nvram_src,	chipc_nvram_src),
502
503	/* NVRAM interface */
504	DEVMETHOD(bhnd_nvram_getvar,	chipc_nvram_getvar),
505	DEVMETHOD(bhnd_nvram_setvar,	chipc_nvram_setvar),
506
507	DEVMETHOD_END
508};
509
510DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
511DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0);
512MODULE_DEPEND(bhnd_chipc, bhnd, 1, 1, 1);
513MODULE_VERSION(bhnd_chipc, 1);
514