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:
Landon J. Fuller 2016-06-04 19:39:05 +00:00
parent 2b693a88f6
commit e129bcd6bc
8 changed files with 805 additions and 6 deletions

View File

@ -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;
}

View File

@ -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);

View 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);

View 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);
}

View 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_ */

View 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);

View 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_ */

View File

@ -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));