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@gmail.com> Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D6250
This commit is contained in:
parent
2b693a88f6
commit
e129bcd6bc
@ -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;
|
||||
}
|
||||
|
@ -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_quirks[] = {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
141
sys/dev/bhnd/cores/chipc/chipc_cfi.c
Normal file
141
sys/dev/bhnd/cores/chipc/chipc_cfi.c
Normal file
@ -0,0 +1,141 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Michael Zhilin <mizhka@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);
|
||||
|
172
sys/dev/bhnd/cores/chipc/chipc_slicer.c
Normal file
172
sys/dev/bhnd/cores/chipc/chipc_slicer.c
Normal file
@ -0,0 +1,172 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Michael Zhilin <mizhka@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);
|
||||
}
|
46
sys/dev/bhnd/cores/chipc/chipc_slicer.h
Normal file
46
sys/dev/bhnd/cores/chipc/chipc_slicer.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Michael Zhilin <mizhka@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_ */
|
280
sys/dev/bhnd/cores/chipc/chipc_spi.c
Normal file
280
sys/dev/bhnd/cores/chipc/chipc_spi.c
Normal file
@ -0,0 +1,280 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Michael Zhilin <mizhka@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);
|
94
sys/dev/bhnd/cores/chipc/chipc_spi.h
Normal file
94
sys/dev/bhnd/cores/chipc/chipc_spi.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Michael Zhilin <mizhka@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_ */
|
@ -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, uart_devinfo) uart_sysdevs;
|
||||
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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user