svn commit: r301409 - in head/sys: dev/bhnd/cores/chipc mips/broadcom

Landon J. Fuller landonf at FreeBSD.org
Sat Jun 4 19:39:07 UTC 2016


Author: landonf
Date: Sat Jun  4 19:39:05 2016
New Revision: 301409
URL: https://svnweb.freebsd.org/changeset/base/301409

Log:
  bhnd(4): Add support for chipc-attached flash
  
  This adds support for serial (via SPI) and parallel (via CFI) flash
  as found on BCM47xx/BCM53xx SoCs.
  
  Submitted by:   Michael Zhilin <mizhka at gmail.com>
  Approved by:    adrian (mentor)
  Differential Revision:  https://reviews.freebsd.org/D6250

Added:
  head/sys/dev/bhnd/cores/chipc/chipc_cfi.c   (contents, props changed)
  head/sys/dev/bhnd/cores/chipc/chipc_slicer.c   (contents, props changed)
  head/sys/dev/bhnd/cores/chipc/chipc_slicer.h   (contents, props changed)
  head/sys/dev/bhnd/cores/chipc/chipc_spi.c   (contents, props changed)
  head/sys/dev/bhnd/cores/chipc/chipc_spi.h   (contents, props changed)
Modified:
  head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
  head/sys/dev/bhnd/cores/chipc/chipc.c
  head/sys/mips/broadcom/uart_bus_chipc.c

Modified: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m	Sat Jun  4 19:31:06 2016	(r301408)
+++ head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m	Sat Jun  4 19:39:05 2016	(r301409)
@@ -28,7 +28,6 @@
 #include <sys/bus.h>
 
 #include <dev/bhnd/bhnd.h>
-#include <dev/bhnd/nvram/bhnd_nvram.h>
 
 INTERFACE bhnd_chipc;
 
@@ -37,6 +36,7 @@ INTERFACE bhnd_chipc;
 #
 
 HEADER {
+	#include <dev/bhnd/nvram/bhnd_nvram.h>
 	/* forward declarations */
 	struct chipc_caps;
 	struct chipc_caps	*bhnd_chipc_generic_get_caps(device_t dev);
@@ -123,3 +123,12 @@ METHOD int enable_sprom {
 METHOD void disable_sprom {
 	device_t dev;
 }
+
+/**
+ * Return the flash configuration register value
+ *
+ * @param dev A bhnd(4) ChipCommon device
+ */
+METHOD uint32_t get_flash_cfg {
+	device_t dev;
+}

Modified: head/sys/dev/bhnd/cores/chipc/chipc.c
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/chipc.c	Sat Jun  4 19:31:06 2016	(r301408)
+++ head/sys/dev/bhnd/cores/chipc/chipc.c	Sat Jun  4 19:39:05 2016	(r301409)
@@ -39,19 +39,36 @@ __FBSDID("$FreeBSD$");
  * and bcma(4) interconnects, providing a common interface to chipset 
  * identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO, 
  * flash, etc.
+ *
+ * The purpose of this driver is memory resource management for ChipCommon drivers
+ * like UART, PMU, flash. ChipCommon core has several memory regions.
+ *
+ * ChipCommon driver has memory resource manager. Driver
+ * gets information about BHND core ports/regions and map them
+ * into drivers' resources.
+ *
+ * Here is overview of mapping:
+ *
+ * ------------------------------------------------------
+ * | Port.Region| Purpose				|
+ * ------------------------------------------------------
+ * |	0.0	| PMU, SPI(0x40), UART(0x300)           |
+ * |	1.0	| ?					|
+ * |	1.1	| MMIO flash (SPI & CFI)		|
+ * ------------------------------------------------------
  */
 
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/bus.h>
+#include <sys/rman.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/systm.h>
 
 #include <machine/bus.h>
-#include <sys/rman.h>
 #include <machine/resource.h>
 
 #include <dev/bhnd/bhnd.h>
@@ -99,6 +116,18 @@ static struct bhnd_device_quirk chipc_qu
 };
 
 
+/*
+ * Here is resource configuration hints for child devices
+ *
+ * [Flash] There are 2 flash resources:
+ *  - resource ID (rid) = 0: memory-mapped flash memory
+ *  - resource ID (rid) = 1: memory-mapped flash registers (i.e for SPI)
+ *
+ * [UART] Uses IRQ and memory resources:
+ *  - resource ID (rid) = 0: memory-mapped registers
+ *  - IRQ resource ID (rid) = 0: shared IRQ line for Tx/Rx.
+ */
+
 static const struct chipc_hint {
 	const char	*name;
 	int		 unit;
@@ -1288,6 +1317,15 @@ chipc_get_caps(device_t dev)
 	return (&sc->caps);
 }
 
+static uint32_t
+chipc_get_flash_cfg(device_t dev)
+{
+	struct chipc_softc	*sc;
+
+	sc = device_get_softc(dev);
+	return (bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG));
+}
+
 static device_method_t chipc_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			chipc_probe),
@@ -1330,11 +1368,13 @@ static device_method_t chipc_methods[] =
 	DEVMETHOD(bhnd_chipc_enable_sprom,	chipc_enable_sprom_pins),
 	DEVMETHOD(bhnd_chipc_disable_sprom,	chipc_disable_sprom_pins),
 	DEVMETHOD(bhnd_chipc_get_caps,		chipc_get_caps),
+	DEVMETHOD(bhnd_chipc_get_flash_cfg,	chipc_get_flash_cfg),
 
 	DEVMETHOD_END
 };
 
 DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
-DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0);
+EARLY_DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0,
+    BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
 MODULE_DEPEND(bhnd_chipc, bhnd, 1, 1, 1);
 MODULE_VERSION(bhnd_chipc, 1);

Added: head/sys/dev/bhnd/cores/chipc/chipc_cfi.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/bhnd/cores/chipc/chipc_cfi.c	Sat Jun  4 19:39:05 2016	(r301409)
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/conf.h>
+
+#include <machine/bus.h>
+
+#include <dev/bhnd/bhnd_debug.h>
+#include <dev/cfi/cfi_var.h>
+
+#include "bhnd_chipc_if.h"
+#include "chipc_slicer.h"
+#include "chipcreg.h"
+#include "chipcvar.h"
+
+/*
+ * **************************** PROTOTYPES ****************************
+ */
+
+static void	chipc_cfi_identify(driver_t *driver, device_t parent);
+static int	chipc_cfi_probe(device_t dev);
+static int	chipc_cfi_attach(device_t dev);
+
+/*
+ * **************************** IMPLEMENTATION ************************
+ */
+
+static void
+chipc_cfi_identify(driver_t *driver, device_t parent)
+{
+	struct chipc_caps	*caps;
+
+	if (device_find_child(parent, cfi_driver_name, -1) != NULL)
+		return;
+
+	caps = BHND_CHIPC_GET_CAPS(parent);
+	if (caps == NULL)
+		return;
+
+	if (caps->flash_type != CHIPC_PFLASH_CFI)
+		return;
+
+	BUS_ADD_CHILD(parent, 0, cfi_driver_name, -1);
+	return;
+}
+
+static int
+chipc_cfi_probe(device_t dev)
+{
+	int			error;
+	int			enabled;
+	int			byteswap;
+	uint32_t		flash_config;
+	struct cfi_softc	*sc;
+
+	sc = device_get_softc(dev);
+
+	flash_config = BHND_CHIPC_GET_FLASH_CFG(device_get_parent(dev));
+
+	enabled = (flash_config & CHIPC_CF_EN);
+	byteswap = (flash_config & CHIPC_CF_BS);
+
+	if (enabled == 0)
+		device_disable(dev);
+
+	BHND_DEBUG_DEV(dev, "trying attach flash enabled=%d swapbytes=%d",
+	    enabled, byteswap);
+
+	sc->sc_width = 0;
+	error = cfi_probe(dev);
+	if (error == 0)
+		device_set_desc(dev, "ChipCommon CFI");
+	return (error);
+}
+
+static int
+chipc_cfi_attach(device_t dev)
+{
+	int	error;
+
+	error = cfi_attach(dev);
+	if (error)
+		return (error);
+
+	flash_register_slicer(chipc_slicer_cfi);
+	return (0);
+}
+
+static device_method_t chipc_cfi_methods[] = {
+	/* device interface */
+	DEVMETHOD(device_identify,	chipc_cfi_identify),
+	DEVMETHOD(device_probe,		chipc_cfi_probe),
+	DEVMETHOD(device_attach,	chipc_cfi_attach),
+	DEVMETHOD(device_detach,	cfi_detach),
+
+	{0, 0}
+};
+
+static driver_t chipc_cfi_driver = {
+	cfi_driver_name,
+	chipc_cfi_methods,
+	sizeof(struct cfi_softc),
+};
+
+DRIVER_MODULE(cfi, bhnd_chipc, chipc_cfi_driver, cfi_devclass, 0, 0);
+

Added: head/sys/dev/bhnd/cores/chipc/chipc_slicer.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/bhnd/cores/chipc/chipc_slicer.c	Sat Jun  4 19:39:05 2016	(r301409)
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Slicer is required to split firmware images into pieces.
+ * The first supported FW is TRX-based used by Asus routers
+ * TODO: add NetGear FW (CHK)
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/errno.h>
+#include <sys/rman.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <sys/slicer.h>
+
+#include <machine/bus.h>
+
+#include <dev/bhnd/bhnd_debug.h>
+
+#include "chipc_slicer.h"
+
+#include <dev/cfi/cfi_var.h>
+#include "chipc_spi.h"
+
+static int	chipc_slicer_walk(device_t dev, struct resource* res,
+		    struct flash_slice *slices, int *nslices);
+
+int
+chipc_slicer_cfi(device_t dev, struct flash_slice *slices, int *nslices)
+{
+	struct cfi_softc	*sc;
+
+	if (strcmp("cfi", device_get_name(dev)) != 0)
+		return (0);
+
+	sc = device_get_softc(dev);
+
+	return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices));
+}
+
+int
+chipc_slicer_spi(device_t dev, struct flash_slice *slices, int *nslices)
+{
+	/* flash(mx25l) <- spibus <- chipc_spi */
+	device_t		 spibus;
+	device_t		 chipc_spi;
+	struct chipc_spi_softc	*sc;
+
+	BHND_DEBUG_DEV(dev, "initting SPI slicer: %s", device_get_name(dev));
+
+	if (strcmp("mx25l", device_get_name(dev)) != 0)
+		return (EINVAL);
+
+	spibus = device_get_parent(dev);
+	if (spibus == NULL) {
+		BHND_ERROR_DEV(dev, "no found ChipCommon SPI BUS device");
+		return (EINVAL);
+	}
+
+	chipc_spi = device_get_parent(spibus);
+	if (chipc_spi == NULL) {
+		BHND_ERROR_DEV(spibus, "no found ChipCommon SPI device");
+		return (EINVAL);
+	}
+
+	sc = device_get_softc(chipc_spi);
+
+	return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices));
+}
+
+/*
+ * Main processing part
+ */
+static int
+chipc_slicer_walk(device_t dev, struct resource* res,
+		struct flash_slice *slices, int *nslices)
+{
+	uint32_t	 fw_len;
+	uint32_t	 fs_ofs;
+	uint32_t	 val;
+	uint32_t	 ofs_trx;
+	int		 flash_size;
+
+	*nslices = 0;
+
+	flash_size = rman_get_size(res);
+	ofs_trx = flash_size;
+
+	BHND_TRACE_DEV(dev, "slicer: scanning memory [%x bytes] for headers...",
+	    flash_size);
+
+	/* Find FW header in flash memory with step=128Kb (0x1000) */
+	for(uint32_t ofs = 0; ofs < flash_size; ofs+= 0x1000){
+		val = bus_read_4(res, ofs);
+		switch (val) {
+		case TRX_MAGIC:
+			/* check for second TRX */
+			if (ofs_trx < ofs) {
+				BHND_TRACE_DEV(dev, "stop on 2nd TRX: %x", ofs);
+				break;
+			}
+
+			BHND_TRACE("TRX found: %x", ofs);
+			ofs_trx = ofs;
+			/* read last offset of TRX header */
+			fs_ofs = bus_read_4(res, ofs + 24);
+			BHND_TRACE("FS offset: %x", fs_ofs);
+
+			/*
+			 * GEOM IO will panic if offset is not aligned
+			 * on sector size, i.e. 512 bytes
+			 */
+			if (fs_ofs % 0x200 != 0) {
+				BHND_WARN("WARNING! filesystem offset should be"
+				    " aligned on sector size (%d bytes)", 0x200);
+				BHND_WARN("ignoring TRX firmware image");
+				break;
+			}
+
+			slices[*nslices].base = ofs + fs_ofs;
+			//XXX: fully sized? any other partition?
+			fw_len = bus_read_4(res, ofs + 4);
+			slices[*nslices].size = fw_len - fs_ofs;
+			slices[*nslices].label = "rootfs";
+			*nslices += 1;
+			break;
+		case CFE_MAGIC:
+			BHND_TRACE("CFE found: %x", ofs);
+			break;
+		case NVRAM_MAGIC:
+			BHND_TRACE("NVRAM found: %x", ofs);
+			break;
+		default:
+			break;
+		}
+	}
+
+	BHND_TRACE("slicer: done");
+	return (0);
+}

Added: head/sys/dev/bhnd/cores/chipc/chipc_slicer.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/bhnd/cores/chipc/chipc_slicer.h	Sat Jun  4 19:39:05 2016	(r301409)
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_CORES_CHIPC_CHIPC_SLICER_H_
+#define _BHND_CORES_CHIPC_CHIPC_SLICER_H_
+
+#include <sys/slicer.h>
+
+#define	TRX_MAGIC 	0x30524448
+#define	CFE_MAGIC 	0x43464531
+#define	NVRAM_MAGIC	0x48534C46
+
+int		chipc_slicer_spi(device_t dev, struct flash_slice *slices,
+		    int *nslices);
+int		chipc_slicer_cfi(device_t dev, struct flash_slice *slices,
+		    int *nslices);
+
+#endif /* _BHND_CORES_CHIPC_CHIPC_SLICER_H_ */

Added: head/sys/dev/bhnd/cores/chipc/chipc_spi.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/bhnd/cores/chipc/chipc_spi.c	Sat Jun  4 19:39:05 2016	(r301409)
@@ -0,0 +1,280 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/errno.h>
+#include <sys/rman.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <dev/bhnd/bhndvar.h>
+/*
+ * SPI BUS interface
+ */
+#include <dev/spibus/spi.h>
+
+#include "spibus_if.h"
+
+#include "chipcreg.h"
+#include "chipcvar.h"
+#include "chipc_spi.h"
+#include "bhnd_chipc_if.h"
+
+/*
+ * Flash slicer
+ */
+#include "chipc_slicer.h"
+
+/*
+ * **************************** PROTOTYPES ****************************
+ */
+
+static void	chipc_spi_identify(driver_t *driver, device_t parent);
+static int	chipc_spi_probe(device_t dev);
+static int	chipc_spi_attach(device_t dev);
+static int	chipc_spi_transfer(device_t dev, device_t child,
+		    struct spi_command *cmd);
+static int	chipc_spi_txrx(struct chipc_spi_softc *sc, uint8_t in,
+		    uint8_t* out);
+static int	chipc_spi_wait(struct chipc_spi_softc *sc);
+
+/*
+ * **************************** IMPLEMENTATION ************************
+ */
+
+static void
+chipc_spi_identify(driver_t *driver, device_t parent)
+{
+	struct chipc_caps	*caps;
+	device_t	 	 spidev;
+	device_t	 	 spibus;
+	device_t 		 flash;
+	char*		 	 flash_name;
+	int		 	 err;
+
+	flash_name = NULL;
+
+	if (device_find_child(parent, "spi", -1) != NULL)
+		return;
+
+	caps = BHND_CHIPC_GET_CAPS(parent);
+	if (caps == NULL) {
+		BHND_ERROR_DEV(parent, "can't retrieve ChipCommon capabilities");
+		return;
+	}
+
+	switch (caps->flash_type) {
+	case CHIPC_SFLASH_AT:
+		flash_name = "at45d";
+		break;
+	case CHIPC_SFLASH_ST:
+		flash_name = "mx25l";
+		break;
+	default:
+		return;
+	}
+
+	spidev = BUS_ADD_CHILD(parent, 0, "spi", -1);
+	if (spidev == NULL) {
+		BHND_ERROR_DEV(parent, "can't add chipc_spi to ChipCommon");
+		return;
+	}
+
+	err = device_probe_and_attach(spidev);
+	if (err) {
+		BHND_ERROR_DEV(spidev, "failed attach chipc_spi: %d", err);
+		return;
+	}
+
+	spibus = device_find_child(spidev, "spibus", -1);
+	if (spibus == NULL) {
+		BHND_ERROR_DEV(spidev, "can't find spibus under chipc_spi");
+		return;
+	}
+
+	flash = BUS_ADD_CHILD(spibus, 0, flash_name, -1);
+	if (flash == NULL) {
+		BHND_ERROR_DEV(spibus, "can't add %s to spibus", flash_name);
+		return;
+	}
+
+	err = device_probe_and_attach(flash);
+	if (err)
+		BHND_ERROR_DEV(flash, "failed attach flash %s: %d", flash_name,
+		    err);
+
+	return;
+}
+
+static int
+chipc_spi_probe(device_t dev)
+{
+	device_set_desc(dev, "ChipCommon SPI");
+	return (BUS_PROBE_DEFAULT);
+}
+
+struct resource_spec	spec_mem[] = {
+		{SYS_RES_MEMORY, 0, RF_ACTIVE},
+		{SYS_RES_MEMORY, 1, RF_ACTIVE},
+		{ -1, -1, 0 }
+	};
+
+static int
+chipc_spi_attach(device_t dev)
+{
+	int 			 err;
+	struct chipc_spi_softc	*sc;
+	struct resource		*mem[2];
+
+	sc = device_get_softc(dev);
+	err = bus_alloc_resources(dev, spec_mem, mem);
+	if (err != 0)
+		return (ENXIO);
+
+	sc->sc_res = mem[0];
+	sc->sc_mem_res = mem[1];
+
+	flash_register_slicer(chipc_slicer_spi);
+	device_add_child(dev, "spibus", 0);
+	return (bus_generic_attach(dev));
+}
+
+static int
+chipc_spi_wait(struct chipc_spi_softc *sc)
+{
+	int i;
+
+	for (i = CHIPC_SPI_MAXTRIES; i > 0; i--)
+		if (!(SPI_READ(sc, CHIPC_SPI_FLASHCTL) & CHIPC_SPI_FLASHCTL_START))
+			break;
+
+	if (i > 0)
+		return (0);
+
+	BHND_DEBUG_DEV(sc->dev, "busy");
+	return (-1);
+}
+
+static int
+chipc_spi_txrx(struct chipc_spi_softc *sc, uint8_t out, uint8_t* in)
+{
+	uint32_t ctl;
+
+	ctl = CHIPC_SPI_FLASHCTL_START | CHIPC_SPI_FLASHCTL_CSACTIVE | out;
+	SPI_BARRIER_WRITE(sc);
+	SPI_WRITE(sc, CHIPC_SPI_FLASHCTL, ctl);
+	SPI_BARRIER_WRITE(sc);
+
+	if (chipc_spi_wait(sc))
+		return (-1);
+
+	*in = SPI_READ(sc, CHIPC_SPI_FLASHDATA) & 0xff;
+	return (0);
+}
+
+static int
+chipc_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
+{
+	struct chipc_spi_softc	*sc;
+	uint8_t		*buf_in;
+	uint8_t		*buf_out;
+	int		 i;
+
+	sc = device_get_softc(dev);
+	KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
+	    ("TX/RX command sizes should be equal"));
+	KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
+	    ("TX/RX data sizes should be equal"));
+
+	if (cmd->tx_cmd_sz == 0) {
+		BHND_DEBUG_DEV(child, "size of command is ZERO");
+		return (EIO);
+	}
+
+	SPI_BARRIER_WRITE(sc);
+	SPI_WRITE(sc, CHIPC_SPI_FLASHADDR, 0);
+	SPI_BARRIER_WRITE(sc);
+
+	/*
+	 * Transfer command
+	 */
+	buf_out = (uint8_t *)cmd->tx_cmd;
+	buf_in = (uint8_t *)cmd->rx_cmd;
+	for (i = 0; i < cmd->tx_cmd_sz; i++)
+		 if (chipc_spi_txrx(sc, buf_out[i], &(buf_in[i])))
+			 return (EIO);
+
+	/*
+	 * Receive/transmit data
+	 */
+	buf_out = (uint8_t *)cmd->tx_data;
+	buf_in = (uint8_t *)cmd->rx_data;
+	for (i = 0; i < cmd->tx_data_sz; i++)
+		if (chipc_spi_txrx(sc, buf_out[i], &(buf_in[i])))
+			return (EIO);
+
+	/*
+	 * Clear CS bit and whole control register
+	 */
+	SPI_BARRIER_WRITE(sc);
+	SPI_WRITE(sc, CHIPC_SPI_FLASHCTL, 0);
+	SPI_BARRIER_WRITE(sc);
+
+	return (0);
+}
+
+/*
+ * **************************** METADATA ************************
+ */
+static device_method_t chipc_spi_methods[] = {
+		DEVMETHOD(device_identify,	chipc_spi_identify),
+		DEVMETHOD(device_probe,		chipc_spi_probe),
+		DEVMETHOD(device_attach,	chipc_spi_attach),
+		/* SPI */
+		DEVMETHOD(spibus_transfer,	chipc_spi_transfer),
+		DEVMETHOD_END
+};
+
+static driver_t chipc_spi_driver = {
+	"spi",
+	chipc_spi_methods,
+	sizeof(struct chipc_spi_softc),
+};
+
+static devclass_t chipc_spi_devclass;
+
+DRIVER_MODULE(chipc_spi, bhnd_chipc, chipc_spi_driver, chipc_spi_devclass,
+		0, 0);

Added: head/sys/dev/bhnd/cores/chipc/chipc_spi.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/bhnd/cores/chipc/chipc_spi.h	Sat Jun  4 19:39:05 2016	(r301409)
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_CORES_CHIPC_CHIPC_SPI_H_
+#define	_BHND_CORES_CHIPC_CHIPC_SPI_H_
+
+#define	CHIPC_SPI_MAXTRIES	1000
+
+#define	CHIPC_SPI_ACTION_INPUT	1
+#define	CHIPC_SPI_ACTION_OUTPUT	2
+
+#define	CHIPC_SPI_FLASHCTL			0x00
+#define		CHIPC_SPI_FLASHCTL_OPCODE	0x000000ff
+#define		CHIPC_SPI_FLASHCTL_ACTION	0x00000700 //
+/*
+ * We don't use action at all. Experimentaly found, that
+ *  action 0 - read current MISO byte to data register (interactive mode)
+ *  action 1 = read 2nd byte to data register
+ *  action 2 = read 4th byte to data register (surprise! see action 6)
+ *  action 3 = read 5th byte to data register
+ *  action 4 = read bytes 5-8 to data register in swapped order
+ *  action 5 = read bytes 9-12 to data register in swapped order
+ *  action 6 = read 3rd byte to data register
+ *  action 7 = read bytes 6-9 to data register in swapped order
+ * It may be wrong if CS bit is 1.
+ * If CS bit is 1, you should write cmd / data to opcode byte-to-byte.
+ */
+#define		CHIPC_SPI_FLASHCTL_CSACTIVE	0x00001000
+#define		CHIPC_SPI_FLASHCTL_START	0x80000000 //same as BUSY
+#define		CHIPC_SPI_FLASHCTL_BUSY		0x80000000 //same as BUSY
+#define	CHIPC_SPI_FLASHADDR			0x04
+#define	CHIPC_SPI_FLASHDATA			0x08
+
+struct chipc_spi_softc {
+	device_t		 dev;
+
+	/* SPI registers */
+	struct resource		*sc_mem_res;
+
+	/* MMIO flash */
+	struct resource		*sc_res;
+};
+
+/* register space access macros */
+#define	SPI_BARRIER_WRITE(sc)	bus_barrier((sc)->sc_mem_res, 0, 0, 	\
+				    BUS_SPACE_BARRIER_WRITE)
+#define	SPI_BARRIER_READ(sc)	bus_barrier((sc)->sc_mem_res, 0, 0, 	\
+				    BUS_SPACE_BARRIER_READ)
+#define	SPI_BARRIER_RW(sc)	bus_barrier((sc)->sc_mem_res, 0, 0, 	\
+			            BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
+
+#define SPI_WRITE(sc, reg, val) do {					\
+		bus_write_4(sc->sc_mem_res, (reg), (val));		\
+	} while (0)
+
+#define	SPI_READ(sc, reg)	bus_read_4(sc->sc_mem_res, (reg))
+
+#define	SPI_SET_BITS(sc, reg, bits)					\
+	SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
+
+#define	SPI_CLEAR_BITS(sc, reg, bits)					\
+	SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
+
+#endif /* _BHND_CORES_CHIPC_CHIPC_SPI_H_ */

Modified: head/sys/mips/broadcom/uart_bus_chipc.c
==============================================================================
--- head/sys/mips/broadcom/uart_bus_chipc.c	Sat Jun  4 19:31:06 2016	(r301408)
+++ head/sys/mips/broadcom/uart_bus_chipc.c	Sat Jun  4 19:39:05 2016	(r301409)
@@ -45,9 +45,12 @@ __FBSDID("$FreeBSD$");
 #include <dev/uart/uart_bus.h>
 #include <dev/uart/uart_cpu.h>
 
+#include <dev/bhnd/cores/chipc/chipcvar.h>
+
 #include "uart_if.h"
 #include "bhnd_chipc_if.h"
 
+
 static int	uart_chipc_probe(device_t dev);
 
 extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
@@ -55,9 +58,18 @@ extern SLIST_HEAD(uart_devinfo_list, uar
 static void
 uart_chipc_identify(driver_t *driver, device_t parent)
 {
-	struct chipc_capabilities	*caps;
+	struct chipc_caps	*caps;
 
-	caps = BHND_CHIPC_GET_CAPABILITIES(parent);
+	if (device_find_child(parent, "uart", -1) != NULL)
+		return;
+
+	caps = BHND_CHIPC_GET_CAPS(parent);
+
+	if (caps == NULL) {
+		device_printf(parent, "error: can't retrieve ChipCommon "
+		    "capabilities\n");
+		return;
+	}
 
 	if (caps->num_uarts == 0)
 		return;
@@ -74,6 +86,7 @@ uart_chipc_probe(device_t dev)
 	struct uart_softc 	*sc;
 	struct resource		*res;
 	int			 rid;
+	int			 err;
 
 	rid = 0;
 	res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
@@ -97,7 +110,11 @@ uart_chipc_probe(device_t dev)
 	sc->sc_bas.bst = sc->sc_sysdev->bas.bst;
 	sc->sc_bas.bsh = sc->sc_sysdev->bas.bsh;
 
-	bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
+	err = bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
+	if (err) {
+		device_printf(dev, "can't release resource [%d]\n", rid);
+		return (ENXIO);
+	}
 
 	/* We use internal SoC clock generator with non-standart freq MHz */
 	return (uart_bus_probe(dev, 0, sc->sc_sysdev->bas.rclk, 0, 0));


More information about the svn-src-head mailing list