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 <miz...@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 <miz...@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 <miz...@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 <miz...@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 <miz...@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 <miz...@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));
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to