preliminary i2c support via the OC I2C ctrl & betrustedio wrapper
Now with a NetBSD driver (based on the OpenBSD one) that shows the i2c bus, and some prom support. Not tested with a device, waiting on custom Pmod.
This commit is contained in:
463
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_ociic.c
Normal file
463
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_ociic.c
Normal file
@@ -0,0 +1,463 @@
|
|||||||
|
/* $NetBSD$ */
|
||||||
|
/*
|
||||||
|
* Original driver from OpenBSD:
|
||||||
|
* Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
|
||||||
|
*
|
||||||
|
* NetBSD support for the SBusFPGA variant (based on the betrustedio wrapper):
|
||||||
|
* Copyright (c) 2022 Romain Dolbeau <romain@dolbeau.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/device.h>
|
||||||
|
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <machine/autoconf.h>
|
||||||
|
#include <sys/cpu.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
|
||||||
|
#define _I2C_PRIVATE
|
||||||
|
#include <dev/i2c/i2cvar.h>
|
||||||
|
|
||||||
|
#include <machine/param.h>
|
||||||
|
|
||||||
|
//#define CONFIG_CSR_DATA_WIDTH 32
|
||||||
|
//#include "dev/sbus/sbusfpga_csr_i2c.h"
|
||||||
|
|
||||||
|
/* Registers */
|
||||||
|
/* with the betrustedio wrapper to the OC I2C core,
|
||||||
|
prescale register is 16-bits,
|
||||||
|
TXR/RXR are split, CR/SR are split,
|
||||||
|
RESET, EV_* are new */
|
||||||
|
/* #define I2C_PRER_LO 0x0000 */
|
||||||
|
/* #define I2C_PRER_HI 0x0004 */
|
||||||
|
#define I2C_PRER 0x0000
|
||||||
|
#define I2C_CTR 0x0004
|
||||||
|
#define I2C_CTR_EN (1 << 7)
|
||||||
|
#define I2C_CTR_IEN (1 << 6)
|
||||||
|
#define I2C_TXR 0x0008
|
||||||
|
#define I2C_RXR 0x000C
|
||||||
|
#define I2C_CR 0x0010
|
||||||
|
#define I2C_CR_STA (1 << 7)
|
||||||
|
#define I2C_CR_STO (1 << 6)
|
||||||
|
#define I2C_CR_RD (1 << 5)
|
||||||
|
#define I2C_CR_WR (1 << 4)
|
||||||
|
#define I2C_CR_NACK (1 << 3)
|
||||||
|
#define I2C_CR_IACK (1 << 0)
|
||||||
|
#define I2C_SR 0x0014
|
||||||
|
#define I2C_SR_RXNACK (1 << 7)
|
||||||
|
#define I2C_SR_BUSY (1 << 6)
|
||||||
|
#define I2C_SR_AL (1 << 5)
|
||||||
|
#define I2C_SR_TIP (1 << 1)
|
||||||
|
#define I2C_SR_IF (1 << 0)
|
||||||
|
#define I2C_RESET 0x0018
|
||||||
|
#define I2C_EV_SR 0x001C
|
||||||
|
#define I2C_EV_PEND 0x0020
|
||||||
|
#define I2C_EV_ENAB 0x0024
|
||||||
|
|
||||||
|
struct ociic_softc {
|
||||||
|
device_t sc_dev;
|
||||||
|
bus_space_tag_t sc_bustag; /* bus tag */
|
||||||
|
bus_space_handle_t sc_bhregs_i2c; /* bus handle */
|
||||||
|
|
||||||
|
int sc_node;
|
||||||
|
int sc_burst;
|
||||||
|
struct i2c_controller sc_ic;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint8_t
|
||||||
|
ociic_read(struct ociic_softc *sc, bus_size_t reg)
|
||||||
|
{
|
||||||
|
return bus_space_read_1(sc->sc_bustag, sc->sc_bhregs_i2c, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
ociic_write(struct ociic_softc *sc, bus_size_t reg, const uint8_t value)
|
||||||
|
{
|
||||||
|
bus_space_write_1(sc->sc_bustag, sc->sc_bhregs_i2c, reg, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
ociic_set(struct ociic_softc *sc, bus_size_t reg, const uint8_t bits)
|
||||||
|
{
|
||||||
|
ociic_write(sc, reg, ociic_read(sc, reg) | bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
ociic_clr(struct ociic_softc *sc, bus_size_t reg, const uint8_t bits)
|
||||||
|
{
|
||||||
|
ociic_write(sc, reg, ociic_read(sc, reg) & ~bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ociic_match(device_t, cfdata_t, void *);
|
||||||
|
void ociic_attach(device_t, device_t, void *);
|
||||||
|
|
||||||
|
CFATTACH_DECL_NEW(sbusfpga_ociic, sizeof(struct ociic_softc),
|
||||||
|
ociic_match, ociic_attach, NULL, NULL);
|
||||||
|
|
||||||
|
int ociic_acquire_bus(void *, int);
|
||||||
|
void ociic_release_bus(void *, int);
|
||||||
|
int ociic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
|
||||||
|
void *, size_t, int);
|
||||||
|
|
||||||
|
static prop_array_t create_dict(device_t parent);
|
||||||
|
static void add_prop(prop_array_t c, const char *name, const char *compat, u_int addr, int node);
|
||||||
|
|
||||||
|
void ociic_bus_scan(struct device *, struct i2cbus_attach_args *, void *);
|
||||||
|
|
||||||
|
int
|
||||||
|
ociic_match(device_t parent, cfdata_t cf, void *aux)
|
||||||
|
{
|
||||||
|
struct sbus_attach_args *sa = (struct sbus_attach_args *)aux;
|
||||||
|
|
||||||
|
return (strcmp("oc,i2c", sa->sa_name) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ociic_attach(device_t parent, device_t self, void *aux)
|
||||||
|
{
|
||||||
|
struct sbus_attach_args *sa = aux;
|
||||||
|
struct ociic_softc *sc = device_private(self);
|
||||||
|
struct sbus_softc *sbsc = device_private(parent);
|
||||||
|
int sbusburst;
|
||||||
|
struct i2cbus_attach_args iba;
|
||||||
|
uint32_t clock_speed, bus_speed;
|
||||||
|
uint32_t div;
|
||||||
|
|
||||||
|
sc->sc_bustag = sa->sa_bustag;
|
||||||
|
// sc->sc_dmatag = sa->sa_dmatag;
|
||||||
|
sc->sc_dev = self;
|
||||||
|
|
||||||
|
aprint_normal("\n");
|
||||||
|
|
||||||
|
if (sa->sa_nreg < 1) {
|
||||||
|
aprint_error(": Not enough registers spaces\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sc->sc_bustag = faa->fa_iot; */
|
||||||
|
/* sc->sc_node = faa->fa_node; */
|
||||||
|
sc->sc_node = sa->sa_node;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get transfer burst size from PROM
|
||||||
|
*/
|
||||||
|
sbusburst = sbsc->sc_burst;
|
||||||
|
if (sbusburst == 0)
|
||||||
|
sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
|
||||||
|
|
||||||
|
sc->sc_burst = prom_getpropint(sc->sc_node, "burst-sizes", -1);
|
||||||
|
if (sc->sc_burst == -1)
|
||||||
|
/* take SBus burst sizes */
|
||||||
|
sc->sc_burst = sbusburst;
|
||||||
|
|
||||||
|
/* Clamp at parent's burst sizes */
|
||||||
|
sc->sc_burst &= sbusburst;
|
||||||
|
|
||||||
|
aprint_normal_dev(self, "nid 0x%x, bustag %p, burst 0x%x (parent 0x%0x)\n",
|
||||||
|
sc->sc_node,
|
||||||
|
sc->sc_bustag,
|
||||||
|
sc->sc_burst,
|
||||||
|
sbsc->sc_burst);
|
||||||
|
|
||||||
|
/* map registers */
|
||||||
|
if (sbus_bus_map(sc->sc_bustag,
|
||||||
|
sa->sa_reg[0].oa_space /* sa_slot */,
|
||||||
|
sa->sa_reg[0].oa_base /* sa_offset */,
|
||||||
|
sa->sa_reg[0].oa_size /* sa_size */,
|
||||||
|
BUS_SPACE_MAP_LINEAR,
|
||||||
|
&sc->sc_bhregs_i2c) != 0) {
|
||||||
|
aprint_error(": cannot map I2C registers\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pinctrl_byname(sc->sc_node, "default"); */
|
||||||
|
/* clock_enable_all(sc->sc_node); */
|
||||||
|
|
||||||
|
ociic_clr(sc, I2C_CTR, I2C_CTR_EN);
|
||||||
|
|
||||||
|
clock_speed = prom_getpropint(sc->sc_node, "clock-speed", -1);
|
||||||
|
bus_speed = prom_getpropint(sc->sc_node, "bus-speed", -1);
|
||||||
|
|
||||||
|
aprint_normal_dev(self, "clock-speed = %d, bus-speed = %d\n", clock_speed, bus_speed);
|
||||||
|
|
||||||
|
if ((clock_speed > 0) && (bus_speed > 0)) {
|
||||||
|
div = (clock_speed / (5 * bus_speed));
|
||||||
|
if (div > 0)
|
||||||
|
div -= 1;
|
||||||
|
if (div > 0xffff)
|
||||||
|
div = 0xffff;
|
||||||
|
|
||||||
|
/* ociic_write(sc, I2C_PRER_LO, div & 0xff); */
|
||||||
|
/* ociic_write(sc, I2C_PRER_HI, div >> 8); */
|
||||||
|
bus_space_write_2(sc->sc_bustag, sc->sc_bhregs_i2c, I2C_PRER, div);
|
||||||
|
aprint_normal_dev(self, "div = %d\n", div);
|
||||||
|
} else {
|
||||||
|
aprint_error(": invalid clock/bus speed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&sc->sc_ic, 0, sizeof(sc->sc_ic));
|
||||||
|
sc->sc_ic.ic_cookie = sc;
|
||||||
|
sc->sc_ic.ic_acquire_bus = ociic_acquire_bus;
|
||||||
|
sc->sc_ic.ic_release_bus = ociic_release_bus;
|
||||||
|
sc->sc_ic.ic_exec = ociic_exec;
|
||||||
|
|
||||||
|
/* Configure its children */
|
||||||
|
memset(&iba, 0, sizeof(iba));
|
||||||
|
iba.iba_tag = &sc->sc_ic;
|
||||||
|
iba.iba_child_devices = create_dict(self);
|
||||||
|
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
char *compat;
|
||||||
|
uint32_t addr;
|
||||||
|
int node;
|
||||||
|
for (node = prom_firstchild(sc->sc_node); node; node = prom_nextsibling(node)) {
|
||||||
|
if ((name = prom_getpropstring(node, "name")) == NULL)
|
||||||
|
continue;
|
||||||
|
if (name[0] == '\0')
|
||||||
|
continue;
|
||||||
|
if ((compat = prom_getpropstring(node, "compatible")) == NULL)
|
||||||
|
continue;
|
||||||
|
if (compat[0] == '\0')
|
||||||
|
continue;
|
||||||
|
if ((addr = prom_getpropint(node, "addr", -1)) == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
add_prop(iba.iba_child_devices, name, compat, addr, sc->sc_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config_found_ia(self, "i2cbus", &iba, iicbus_print);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ociic_acquire_bus(void *cookie, int flags)
|
||||||
|
{
|
||||||
|
struct ociic_softc *sc = cookie;
|
||||||
|
|
||||||
|
ociic_set(sc, I2C_CTR, I2C_CTR_EN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ociic_release_bus(void *cookie, int flags)
|
||||||
|
{
|
||||||
|
struct ociic_softc *sc = cookie;
|
||||||
|
|
||||||
|
ociic_clr(sc, I2C_CTR, I2C_CTR_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ociic_unbusy(struct ociic_softc *sc);
|
||||||
|
int
|
||||||
|
ociic_unbusy(struct ociic_softc *sc)
|
||||||
|
{
|
||||||
|
uint8_t stat;
|
||||||
|
int timo;
|
||||||
|
|
||||||
|
for (timo = 50000; timo > 0; timo--) {
|
||||||
|
stat = ociic_read(sc, I2C_SR);
|
||||||
|
if ((stat & I2C_SR_BUSY) == 0)
|
||||||
|
break;
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
if (timo == 0) {
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_STO);
|
||||||
|
return ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ociic_wait(struct ociic_softc *sc, int ack);
|
||||||
|
int
|
||||||
|
ociic_wait(struct ociic_softc *sc, int ack)
|
||||||
|
{
|
||||||
|
uint8_t stat;
|
||||||
|
int timo;
|
||||||
|
|
||||||
|
for (timo = 50000; timo > 0; timo--) {
|
||||||
|
stat = ociic_read(sc, I2C_SR);
|
||||||
|
if ((stat & I2C_SR_TIP) == 0)
|
||||||
|
break;
|
||||||
|
if ((stat & I2C_SR_AL))
|
||||||
|
break;
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
if (timo == 0) {
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_STO);
|
||||||
|
return ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat & I2C_SR_AL) {
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_STO);
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
if (ack && (stat & I2C_SR_RXNACK)) {
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_STO);
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ociic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
|
||||||
|
size_t cmdlen, void *buf, size_t buflen, int flags)
|
||||||
|
{
|
||||||
|
struct ociic_softc *sc = cookie;
|
||||||
|
int error, i;
|
||||||
|
|
||||||
|
error = ociic_unbusy(sc);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (cmdlen > 0) {
|
||||||
|
ociic_write(sc, I2C_TXR, addr << 1);
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
|
||||||
|
error = ociic_wait(sc, 1);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
for (i = 0; i < cmdlen; i++) {
|
||||||
|
ociic_write(sc, I2C_TXR, ((const uint8_t *)cmd)[i]);
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_WR);
|
||||||
|
error = ociic_wait(sc, 1);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (I2C_OP_READ_P(op)) {
|
||||||
|
ociic_write(sc, I2C_TXR, addr << 1 | 1);
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
|
||||||
|
error = ociic_wait(sc, 1);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
for (i = 0; i < buflen; i++) {
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_RD |
|
||||||
|
(i == (buflen - 1) ? I2C_CR_NACK : 0));
|
||||||
|
error = ociic_wait(sc, 0);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
((uint8_t *)buf)[i] = ociic_read(sc, I2C_RXR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cmdlen == 0) {
|
||||||
|
ociic_write(sc, I2C_TXR, addr << 1);
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < buflen; i++) {
|
||||||
|
ociic_write(sc, I2C_TXR, ((const uint8_t *)buf)[i]);
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_WR);
|
||||||
|
error = ociic_wait(sc, 1);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (I2C_OP_STOP_P(op))
|
||||||
|
ociic_write(sc, I2C_CR, I2C_CR_STO);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ociic_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
|
||||||
|
{
|
||||||
|
int iba_node = *(int *)arg;
|
||||||
|
struct i2c_attach_args ia;
|
||||||
|
/* char name[32], status[32]; */
|
||||||
|
/* uint32_t reg[1]; */
|
||||||
|
char *name;
|
||||||
|
uint32_t addr;
|
||||||
|
int node;
|
||||||
|
|
||||||
|
/* for (node = OF_child(iba_node); node; node = OF_peer(node)) { */
|
||||||
|
/* memset(name, 0, sizeof(name)); */
|
||||||
|
/* memset(status, 0, sizeof(status)); */
|
||||||
|
/* memset(reg, 0, sizeof(reg)); */
|
||||||
|
|
||||||
|
/* if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) */
|
||||||
|
/* continue; */
|
||||||
|
/* if (name[0] == '\0') */
|
||||||
|
/* continue; */
|
||||||
|
|
||||||
|
/* if (OF_getprop(node, "status", status, sizeof(status)) > 0 && */
|
||||||
|
/* strcmp(status, "disabled") == 0) */
|
||||||
|
/* continue; */
|
||||||
|
|
||||||
|
/* if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) */
|
||||||
|
/* continue; */
|
||||||
|
|
||||||
|
/* memset(&ia, 0, sizeof(ia)); */
|
||||||
|
/* ia.ia_tag = iba->iba_tag; */
|
||||||
|
/* ia.ia_addr = bemtoh32(®[0]); */
|
||||||
|
/* ia.ia_name = name; */
|
||||||
|
/* ia.ia_cookie = &node; */
|
||||||
|
/* config_found(self, &ia, iicbus_print); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
for (node = prom_firstchild(iba_node); node; node = prom_nextsibling(node)) {
|
||||||
|
if ((name = prom_getpropstring(node, "name")) == NULL)
|
||||||
|
continue;
|
||||||
|
if (name[0] == '\0')
|
||||||
|
continue;
|
||||||
|
if ((addr = prom_getpropint(node, "addr", -1)) == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
memset(&ia, 0, sizeof(ia));
|
||||||
|
ia.ia_tag = iba->iba_tag;
|
||||||
|
ia.ia_addr = addr;
|
||||||
|
ia.ia_name = name;
|
||||||
|
ia.ia_cookie = (uintptr_t)&node;
|
||||||
|
config_found(self, &ia, iicbus_print);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stolen from arch/sparc64/dev/pcfiic_ebus.c */
|
||||||
|
static prop_array_t
|
||||||
|
create_dict(device_t parent)
|
||||||
|
{
|
||||||
|
prop_dictionary_t props = device_properties(parent);
|
||||||
|
prop_array_t cfg = prop_dictionary_get(props, "i2c-child-devices");
|
||||||
|
if (cfg) return cfg;
|
||||||
|
cfg = prop_array_create();
|
||||||
|
prop_dictionary_set(props, "i2c-child-devices", cfg);
|
||||||
|
prop_object_release(cfg);
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_prop(prop_array_t c, const char *name, const char *compat, u_int addr, int node)
|
||||||
|
{
|
||||||
|
prop_dictionary_t dev;
|
||||||
|
prop_data_t data;
|
||||||
|
|
||||||
|
dev = prop_dictionary_create();
|
||||||
|
prop_dictionary_set_cstring(dev, "name", name);
|
||||||
|
data = prop_data_create_data(compat, strlen(compat)+1);
|
||||||
|
prop_dictionary_set(dev, "compatible", data);
|
||||||
|
prop_object_release(data);
|
||||||
|
prop_dictionary_set_uint32(dev, "addr", addr);
|
||||||
|
prop_dictionary_set_uint64(dev, "cookie", node);
|
||||||
|
prop_array_add(c, dev);
|
||||||
|
prop_object_release(dev);
|
||||||
|
}
|
||||||
@@ -561,6 +561,7 @@ class SBusFPGABus(Module):
|
|||||||
(SBUS_3V3_PPRD_i == 1)),
|
(SBUS_3V3_PPRD_i == 1)),
|
||||||
NextValue(sbus_oe_master_in, 1),
|
NextValue(sbus_oe_master_in, 1),
|
||||||
If(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ROM_ADDR_PFX) |
|
If(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ROM_ADDR_PFX) |
|
||||||
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == WISHBONE_CSR_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX)),
|
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX)),
|
||||||
@@ -624,6 +625,7 @@ class SBusFPGABus(Module):
|
|||||||
#NextValue(sbus_master_error_virtual, Cat(SBUS_3V3_PA_i, SBUS_3V3_SIZ_i, Signal(1, reset=0))),
|
#NextValue(sbus_master_error_virtual, Cat(SBUS_3V3_PA_i, SBUS_3V3_SIZ_i, Signal(1, reset=0))),
|
||||||
NextState("Slave_Error")
|
NextState("Slave_Error")
|
||||||
).Elif(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ROM_ADDR_PFX) |
|
).Elif(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ROM_ADDR_PFX) |
|
||||||
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == WISHBONE_CSR_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_FHC_ADDR_PFX) |
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_FHC_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
|
||||||
@@ -746,7 +748,8 @@ class SBusFPGABus(Module):
|
|||||||
(SIZ_BYTE == SBUS_3V3_SIZ_i) &
|
(SIZ_BYTE == SBUS_3V3_SIZ_i) &
|
||||||
(SBUS_3V3_PPRD_i == 0)),
|
(SBUS_3V3_PPRD_i == 0)),
|
||||||
NextValue(sbus_oe_master_in, 1),
|
NextValue(sbus_oe_master_in, 1),
|
||||||
If(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
|
If(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == WISHBONE_CSR_ADDR_PFX) |
|
||||||
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX)),
|
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX)),
|
||||||
NextValue(sbus_wishbone_le,
|
NextValue(sbus_wishbone_le,
|
||||||
@@ -795,7 +798,8 @@ class SBusFPGABus(Module):
|
|||||||
NextValue(stat_slave_early_error_counter, stat_slave_early_error_counter + 1),
|
NextValue(stat_slave_early_error_counter, stat_slave_early_error_counter + 1),
|
||||||
#NextValue(sbus_master_error_virtual, Cat(SBUS_3V3_PA_i, SBUS_3V3_SIZ_i, Signal(1, reset=0))),
|
#NextValue(sbus_master_error_virtual, Cat(SBUS_3V3_PA_i, SBUS_3V3_SIZ_i, Signal(1, reset=0))),
|
||||||
NextState("Slave_Error")
|
NextState("Slave_Error")
|
||||||
).Elif(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
|
).Elif(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == WISHBONE_CSR_ADDR_PFX) |
|
||||||
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_FHC_ADDR_PFX) |
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_FHC_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
|
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
|
||||||
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX)),
|
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX)),
|
||||||
|
|||||||
@@ -188,8 +188,17 @@ def get_prom(soc,
|
|||||||
r += "finish-device\nnew-device\n"
|
r += "finish-device\nnew-device\n"
|
||||||
|
|
||||||
if (i2c):
|
if (i2c):
|
||||||
r += "\" RDOL,i2c\" device-name\n"
|
r += "\" oc,i2c\" device-name\n"
|
||||||
r += get_header_map_stuff("i2c", "i2c", 64)
|
r += get_header_map_stuff("i2c", "i2c", 64)
|
||||||
|
r += (f"h# {sys_clk_freq:x} encode-int \" clock-speed\" property\n").replace("0x", "")
|
||||||
|
bus_speed = 400000
|
||||||
|
r += (f"h# {bus_speed:x} encode-int \" bus-speed\" property\n").replace("0x", "")
|
||||||
|
# assume just a lm75-compatible device at 0x48 (i.e. the custom Pmod)
|
||||||
|
r += " new-device\n"
|
||||||
|
r += " \" AT30TS74-UFM10\" encode-string \" name\" property\n"
|
||||||
|
r += " \" lm75\" encode-string \" compatible\" property\n"
|
||||||
|
r += " h# 48 encode-int \" addr\" property\n"
|
||||||
|
r += " finish-device\n"
|
||||||
if (framebuffer or sdcard):
|
if (framebuffer or sdcard):
|
||||||
r += "finish-device\nnew-device\n"
|
r += "finish-device\nnew-device\n"
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ from migen.genlib.cdc import BusSynchronizer
|
|||||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
|
||||||
# betrusted-io/gateware
|
# betrusted-io/gateware
|
||||||
from gateware import i2c
|
from gateware.i2c import *
|
||||||
|
|
||||||
import sbus_to_fpga_export
|
import sbus_to_fpga_export
|
||||||
import sbus_to_fpga_prom
|
import sbus_to_fpga_prom
|
||||||
@@ -347,7 +347,11 @@ class SBusFPGA(SoCCore):
|
|||||||
#for i in range(len(prom)):
|
#for i in range(len(prom)):
|
||||||
# print(hex(prom[i]))
|
# print(hex(prom[i]))
|
||||||
#print("\n****************************************\n")
|
#print("\n****************************************\n")
|
||||||
self.add_ram("prom", origin=self.mem_map["prom"], size=2**15, contents=prom_data, mode="r") ### FIXME: round up the prom_data size & check for <= 2**16!
|
prom_len = 4*len(prom_data);
|
||||||
|
rounded_prom_len = 2**log2_int(prom_len, False)
|
||||||
|
print(f"ROM is {prom_len} bytes, using {rounded_prom_len}")
|
||||||
|
assert(rounded_prom_len <= 2**16)
|
||||||
|
self.add_ram("prom", origin=self.mem_map["prom"], size=rounded_prom_len, contents=prom_data, mode="r")
|
||||||
#getattr(self,"prom").mem.init = prom_data
|
#getattr(self,"prom").mem.init = prom_data
|
||||||
#getattr(self,"prom").mem.depth = 2**15
|
#getattr(self,"prom").mem.depth = 2**15
|
||||||
|
|
||||||
@@ -501,7 +505,7 @@ class SBusFPGA(SoCCore):
|
|||||||
self.comb += self.crg.curve25519_on.eq(self.curve25519engine.power.fields.on)
|
self.comb += self.crg.curve25519_on.eq(self.curve25519engine.power.fields.on)
|
||||||
|
|
||||||
if (i2c):
|
if (i2c):
|
||||||
self.submodules.i2c = i2c.RTLI2C(platform, pads=platform.request("i2c"))
|
self.submodules.i2c = RTLI2C(platform, pads=platform.request("i2c"))
|
||||||
|
|
||||||
if (framebuffer):
|
if (framebuffer):
|
||||||
self.submodules.videophy = VideoVGAPHY(platform.request("vga"), clock_domain="vga")
|
self.submodules.videophy = VideoVGAPHY(platform.request("vga"), clock_domain="vga")
|
||||||
@@ -524,7 +528,11 @@ class SBusFPGA(SoCCore):
|
|||||||
self.bus.add_master(name="cg6_accel_r5_d", master=self.cg6_accel.dbus)
|
self.bus.add_master(name="cg6_accel_r5_d", master=self.cg6_accel.dbus)
|
||||||
cg6_rom_file = "blit.raw"
|
cg6_rom_file = "blit.raw"
|
||||||
cg6_rom_data = soc_core.get_mem_data(cg6_rom_file, "little")
|
cg6_rom_data = soc_core.get_mem_data(cg6_rom_file, "little")
|
||||||
self.add_ram("cg6_accel_rom", origin=self.mem_map["cg6_accel_rom"], size=2**13, contents=cg6_rom_data, mode="r")
|
cg6_rom_len = 4*len(cg6_rom_data);
|
||||||
|
rounded_cg6_rom_len = 2**log2_int(cg6_rom_len, False)
|
||||||
|
print(f"CG6 ROM is {cg6_rom_len} bytes, using {rounded_cg6_rom_len}")
|
||||||
|
assert(rounded_cg6_rom_len <= 2**16)
|
||||||
|
self.add_ram("cg6_accel_rom", origin=self.mem_map["cg6_accel_rom"], size=rounded_cg6_rom_len, contents=cg6_rom_data, mode="r")
|
||||||
self.add_ram("cg6_accel_ram", origin=self.mem_map["cg6_accel_ram"], size=2**12, mode="rw")
|
self.add_ram("cg6_accel_ram", origin=self.mem_map["cg6_accel_ram"], size=2**12, mode="rw")
|
||||||
|
|
||||||
print("IRQ to Device map:\n")
|
print("IRQ to Device map:\n")
|
||||||
|
|||||||
@@ -196,12 +196,22 @@ _i2c_v1_0 = [
|
|||||||
IOStandard("LVCMOS33"))
|
IOStandard("LVCMOS33"))
|
||||||
]
|
]
|
||||||
# reusing the UART pins !!!
|
# reusing the UART pins !!!
|
||||||
_i2c_v1_2 = [
|
#_i2c_v1_2 = [
|
||||||
("i2c", 0,
|
# ("i2c", 0,
|
||||||
Subsignal("scl", Pins("V9")),
|
# Subsignal("scl", Pins("V9")),
|
||||||
Subsignal("sda", Pins("U9")),
|
# Subsignal("sda", Pins("U9")),
|
||||||
IOStandard("LVCMOS33"))
|
# IOStandard("LVCMOS33"))
|
||||||
|
#]
|
||||||
|
|
||||||
|
def tempi2c_pmod_io(pmod):
|
||||||
|
return [
|
||||||
|
("i2c", 0,
|
||||||
|
Subsignal("scl", Pins(f"{pmod}:3"), Misc("PULLUP True")),
|
||||||
|
Subsignal("sda", Pins(f"{pmod}:7"), Misc("PULLUP True")),
|
||||||
|
IOStandard("LVCMOS33"),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
_tempi2c_pmod_io_v1_2 = tempi2c_pmod_io("P1")
|
||||||
|
|
||||||
# VGA ----------------------------------------------------------------------------------------------
|
# VGA ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -272,7 +282,7 @@ class Platform(XilinxPlatform):
|
|||||||
}[version]
|
}[version]
|
||||||
i2c = {
|
i2c = {
|
||||||
"V1.0" : _i2c_v1_0,
|
"V1.0" : _i2c_v1_0,
|
||||||
"V1.2" : _i2c_v1_2,
|
"V1.2" : _tempi2c_pmod_io_v1_2,
|
||||||
}[version]
|
}[version]
|
||||||
self.avail_irqs = {
|
self.avail_irqs = {
|
||||||
"V1.0" : { 1 }, # don't add 7 here, too risky
|
"V1.0" : { 1 }, # don't add 7 here, too risky
|
||||||
@@ -288,6 +298,12 @@ class Platform(XilinxPlatform):
|
|||||||
self.add_extension(sbus_io)
|
self.add_extension(sbus_io)
|
||||||
self.add_extension(sbus_sbus)
|
self.add_extension(sbus_sbus)
|
||||||
self.add_extension(i2c)
|
self.add_extension(i2c)
|
||||||
|
|
||||||
|
self.toolchain.opt_directive = "Explore"
|
||||||
|
#self.toolchain.vivado_place_directive = "Explore"
|
||||||
|
self.toolchain.vivado_post_place_phys_opt_directive = "Explore"
|
||||||
|
#self.toolchain.vivado_route_directive = "Explore"
|
||||||
|
self.toolchain.vivado_post_route_phys_opt_directive = "Explore"
|
||||||
|
|
||||||
self.toolchain.bitstream_commands = \
|
self.toolchain.bitstream_commands = \
|
||||||
["set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR No [current_design]",
|
["set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR No [current_design]",
|
||||||
|
|||||||
Reference in New Issue
Block a user