summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2022-05-19 13:55:43 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2022-05-19 13:55:43 +0200
commit764fdbaba337e3b58f31ce7b177c4e7c0ba2088d (patch)
tree954b7c40be6beb5ab6ca9158840e93873cc43427 /drivers
parent28889ccbfe785c59bfaa7c39985c376b697e2331 (diff)
parent747146a3eb186fb7101f1aaab53d9188dc41bfbb (diff)
downloadbarebox-764fdbaba337e3b58f31ce7b177c4e7c0ba2088d.tar.gz
barebox-764fdbaba337e3b58f31ce7b177c4e7c0ba2088d.tar.xz
Merge branch 'for-next/misc'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/disk_ata_drive.c23
-rw-r--r--drivers/i2c/busses/Kconfig8
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-cadence.c453
-rw-r--r--drivers/i2c/busses/i2c-rockchip.c13
-rw-r--r--drivers/phy/rockchip/phy-rockchip-naneng-combphy.c19
-rw-r--r--drivers/serial/serial_ns16550.c14
-rw-r--r--drivers/spi/Kconfig6
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-sifive.c521
-rw-r--r--drivers/usb/dwc3/core.c50
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/omap.c3
13 files changed, 1060 insertions, 54 deletions
diff --git a/drivers/ata/disk_ata_drive.c b/drivers/ata/disk_ata_drive.c
index f36e06328c..7df0879b19 100644
--- a/drivers/ata/disk_ata_drive.c
+++ b/drivers/ata/disk_ata_drive.c
@@ -80,9 +80,9 @@ static void __maybe_unused ata_dump_id(uint16_t *id)
ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
printf("Product model number: %s\n\r", product);
- /* Total sectors of device */
+ /* Total sectors of device */
n_sectors = ata_id_n_sectors(id);
- printf("Capablity: %lld sectors\n\r", n_sectors);
+ printf("Capacity: %lld sectors\n\r", n_sectors);
printf ("id[49]: capabilities = 0x%04x\n"
"id[53]: field valid = 0x%04x\n"
@@ -95,12 +95,14 @@ static void __maybe_unused ata_dump_id(uint16_t *id)
id[ATA_ID_PIO_MODES],
id[ATA_ID_QUEUE_DEPTH]);
- printf ("id[76]: sata capablity = 0x%04x\n"
+ printf ("id[76]: sata capabilities 1 = 0x%04x\n"
+ "id[77]: sata capabilities 2 = 0x%04x\n"
"id[78]: sata features supported = 0x%04x\n"
- "id[79]: sata features enable = 0x%04x\n",
- id[76], /* FIXME */
- id[78], /* FIXME */
- id[79]); /* FIXME */
+ "id[79]: sata features enabled = 0x%04x\n",
+ id[ATA_ID_SATA_CAPAB_1],
+ id[ATA_ID_SATA_CAPAB_2],
+ id[ATA_ID_SATA_FEAT_SUPP],
+ id[ATA_ID_SATA_FEAT_ENABLE]);
printf ("id[80]: major version = 0x%04x\n"
"id[81]: minor version = 0x%04x\n"
@@ -108,12 +110,13 @@ static void __maybe_unused ata_dump_id(uint16_t *id)
"id[83]: command set supported 2 = 0x%04x\n"
"id[84]: command set extension = 0x%04x\n",
id[ATA_ID_MAJOR_VER],
- id[81], /* FIXME */
+ id[ATA_ID_MINOR_VER],
id[ATA_ID_COMMAND_SET_1],
id[ATA_ID_COMMAND_SET_2],
id[ATA_ID_CFSSE]);
- printf ("id[85]: command set enable 1 = 0x%04x\n"
- "id[86]: command set enable 2 = 0x%04x\n"
+
+ printf ("id[85]: command set enabled 1 = 0x%04x\n"
+ "id[86]: command set enabled 2 = 0x%04x\n"
"id[87]: command set default = 0x%04x\n"
"id[88]: udma = 0x%04x\n"
"id[93]: hardware reset result = 0x%04x\n",
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d4e74552b7..58f8656067 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -70,4 +70,12 @@ config I2C_RK3X
Say Y here to include support for the I2C adapter in Rockchip RK3xxx
SoCs.
+config I2C_CADENCE
+ bool "Cadence I2C adapter"
+ depends on HAVE_CLK
+ depends on ARCH_ZYNQMP || COMPILE_TEST
+ help
+ Say Y here to include support for the Cadence I2C host controller found
+ in Zynq UltraScale+ MPSoCs.
+
endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index d6273f3d86..a8661f605e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_DESIGNWARE) += i2c-designware.o
obj-$(CONFIG_I2C_STM32) += i2c-stm32.o
obj-$(CONFIG_I2C_RK3X) += i2c-rockchip.o
+obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
new file mode 100644
index 0000000000..5537efff23
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * I2C bus driver for the Cadence I2C host controller (master only).
+ *
+ * Partly based on the driver in the Linux kernel
+ * Copyright (C) 2009 - 2014 Xilinx, Inc.
+ *
+ * Copyright (C) 2022 Matthias Fend <matthias.fend@emfend.at>
+ */
+
+#include <common.h>
+#include <i2c/i2c.h>
+#include <linux/iopoll.h>
+#include <errno.h>
+#include <linux/err.h>
+#include <driver.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <regmap.h>
+
+struct __packed i2c_regs {
+ u32 control;
+ u32 status;
+ u32 address;
+ u32 data;
+ u32 interrupt_status;
+ u32 transfer_size;
+ u32 slave_mon_pause;
+ u32 time_out;
+ u32 interrupt_mask;
+ u32 interrupt_enable;
+ u32 interrupt_disable;
+ u32 glitch_filter;
+};
+
+/* Control register fields */
+#define CDNS_I2C_CONTROL_RW BIT(0)
+#define CDNS_I2C_CONTROL_MS BIT(1)
+#define CDNS_I2C_CONTROL_NEA BIT(2)
+#define CDNS_I2C_CONTROL_ACKEN BIT(3)
+#define CDNS_I2C_CONTROL_HOLD BIT(4)
+#define CDNS_I2C_CONTROL_SLVMON BIT(5)
+#define CDNS_I2C_CONTROL_CLR_FIFO BIT(6)
+#define CDNS_I2C_CONTROL_DIV_B_SHIFT 8
+#define CDNS_I2C_CONTROL_DIV_B_MASK (0x3F << CDNS_I2C_CONTROL_DIV_B_SHIFT)
+#define CDNS_I2C_CONTROL_DIV_A_SHIFT 14
+#define CDNS_I2C_CONTROL_DIV_A_MASK (0x03 << CDNS_I2C_CONTROL_DIV_A_SHIFT)
+
+#define CDNS_I2C_CONTROL_DIV_B_MAX 64
+#define CDNS_I2C_CONTROL_DIV_A_MAX 4
+
+/* Status register fields */
+#define CDNS_I2C_STATUS_RXRW BIT(3)
+#define CDNS_I2C_STATUS_RXDV BIT(5)
+#define CDNS_I2C_STATUS_TXDV BIT(6)
+#define CDNS_I2C_STATUS_RXOVF BIT(7)
+#define CDNS_I2C_STATUS_BA BIT(8)
+
+/* Address register fields */
+#define CDNS_I2C_ADDRESS_MASK 0x3FF
+
+/* Interrupt register fields */
+#define CDNS_I2C_INTERRUPT_COMP BIT(0)
+#define CDNS_I2C_INTERRUPT_DATA BIT(1)
+#define CDNS_I2C_INTERRUPT_NACK BIT(2)
+#define CDNS_I2C_INTERRUPT_TO BIT(3)
+#define CDNS_I2C_INTERRUPT_SLVRDY BIT(4)
+#define CDNS_I2C_INTERRUPT_RXOVF BIT(5)
+#define CDNS_I2C_INTERRUPT_TXOVF BIT(6)
+#define CDNS_I2C_INTERRUPT_RXUNF BIT(7)
+#define CDNS_I2C_INTERRUPT_ARBLOST BIT(9)
+
+#define CDNS_I2C_INTERRUPTS_MASK_MASTER (CDNS_I2C_INTERRUPT_COMP | \
+ CDNS_I2C_INTERRUPT_DATA | \
+ CDNS_I2C_INTERRUPT_NACK | \
+ CDNS_I2C_INTERRUPT_RXOVF | \
+ CDNS_I2C_INTERRUPT_TXOVF | \
+ CDNS_I2C_INTERRUPT_RXUNF | \
+ CDNS_I2C_INTERRUPT_ARBLOST)
+
+#define CDNS_I2C_INTERRUPTS_MASK_ALL (CDNS_I2C_INTERRUPT_COMP | \
+ CDNS_I2C_INTERRUPT_DATA | \
+ CDNS_I2C_INTERRUPT_NACK | \
+ CDNS_I2C_INTERRUPT_TO | \
+ CDNS_I2C_INTERRUPT_SLVRDY | \
+ CDNS_I2C_INTERRUPT_RXOVF | \
+ CDNS_I2C_INTERRUPT_TXOVF | \
+ CDNS_I2C_INTERRUPT_RXUNF | \
+ CDNS_I2C_INTERRUPT_ARBLOST)
+
+#define CDNS_I2C_FIFO_DEPTH 16
+#define CDNS_I2C_TRANSFER_SIZE_MAX 255
+#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_TRANSFER_SIZE_MAX - 3)
+
+#define I2C_TIMEOUT_US (100 * USEC_PER_MSEC)
+
+struct cdns_i2c {
+ struct i2c_adapter adapter;
+ struct clk *clk;
+ struct i2c_regs *regs;
+ bool bus_hold_flag;
+};
+
+static void cdns_i2c_reset_hardware(struct cdns_i2c *i2c)
+{
+ struct i2c_regs *regs = i2c->regs;
+ u32 regval;
+
+ writel(CDNS_I2C_INTERRUPTS_MASK_ALL, &regs->interrupt_disable);
+
+ regval = readl(&regs->control);
+ regval &= ~CDNS_I2C_CONTROL_HOLD;
+ regval |= CDNS_I2C_CONTROL_CLR_FIFO;
+ writel(regval, &regs->control);
+
+ writel(0xFF, &regs->time_out);
+
+ writel(0, &regs->transfer_size);
+
+ regval = readl(&regs->interrupt_status);
+ writel(regval, &regs->interrupt_status);
+
+ regval = readl(&regs->status);
+ writel(regval, &regs->status);
+
+ writel(0, &regs->control);
+}
+
+static void cdns_i2c_setup_master(struct cdns_i2c *i2c)
+{
+ u32 control;
+
+ control = readl(&i2c->regs->control);
+ control |= CDNS_I2C_CONTROL_MS | CDNS_I2C_CONTROL_ACKEN |
+ CDNS_I2C_CONTROL_NEA;
+ writel(control, &i2c->regs->control);
+
+ writel(CDNS_I2C_INTERRUPTS_MASK_MASTER, &i2c->regs->interrupt_enable);
+}
+
+static void cdns_i2c_clear_hold_flag(struct cdns_i2c *i2c)
+{
+ u32 control;
+
+ control = readl(&i2c->regs->control);
+ if (control & CDNS_I2C_CONTROL_HOLD)
+ writel(control & ~CDNS_I2C_CONTROL_HOLD, &i2c->regs->control);
+}
+
+static bool cdns_i2c_is_busy(struct cdns_i2c *i2c)
+{
+ return readl(&i2c->regs->status) & CDNS_I2C_STATUS_BA;
+}
+
+static int cdns_i2c_hw_error(struct cdns_i2c *i2c)
+{
+ u32 isr_status;
+
+ isr_status = readl(&i2c->regs->interrupt_status);
+
+ if (isr_status & CDNS_I2C_INTERRUPT_NACK)
+ return -EREMOTEIO;
+
+ if (isr_status &
+ (CDNS_I2C_INTERRUPT_ARBLOST | CDNS_I2C_INTERRUPT_RXOVF))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int cdns_i2c_wait_for_completion(struct cdns_i2c *i2c)
+{
+ int err;
+ u32 isr_status;
+ const u32 isr_mask =
+ (CDNS_I2C_INTERRUPT_COMP | CDNS_I2C_INTERRUPT_NACK |
+ CDNS_I2C_INTERRUPT_ARBLOST);
+
+ err = readl_poll_timeout(&i2c->regs->interrupt_status, isr_status,
+ isr_status & isr_mask, I2C_TIMEOUT_US);
+
+ if (err)
+ return -ETIMEDOUT;
+
+ return cdns_i2c_hw_error(i2c);
+}
+
+/*
+ * Find best clock divisors
+ *
+ * f = finput / (22 x (div_a + 1) x (div_b + 1))
+ */
+static int cdns_i2c_calc_divs(u32 *f, u32 input_clk, u32 *a, u32 *b)
+{
+ ulong fscl = *f, best_fscl = *f, actual_fscl, temp;
+ uint div_a, div_b, calc_div_a = 0, calc_div_b = 0;
+ uint last_error, current_error;
+
+ temp = input_clk / (22 * fscl);
+
+ if (!temp ||
+ (temp > (CDNS_I2C_CONTROL_DIV_A_MAX * CDNS_I2C_CONTROL_DIV_B_MAX)))
+ return -EINVAL;
+
+ last_error = -1;
+ for (div_a = 0; div_a < CDNS_I2C_CONTROL_DIV_A_MAX; div_a++) {
+ div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
+
+ if ((div_b < 1) || (div_b > CDNS_I2C_CONTROL_DIV_B_MAX))
+ continue;
+ div_b--;
+
+ actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
+
+ if (actual_fscl > fscl)
+ continue;
+
+ current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
+ (fscl - actual_fscl));
+
+ if (last_error > current_error) {
+ calc_div_a = div_a;
+ calc_div_b = div_b;
+ best_fscl = actual_fscl;
+ last_error = current_error;
+ }
+ }
+
+ *a = calc_div_a;
+ *b = calc_div_b;
+ *f = best_fscl;
+
+ return 0;
+}
+
+static int cdns_i2c_set_clk(struct cdns_i2c *i2c, u32 scl_rate)
+{
+ u32 i2c_rate;
+ u32 control;
+ u32 div_a, div_b;
+ int err;
+
+ i2c_rate = clk_get_rate(i2c->clk);
+
+ err = cdns_i2c_calc_divs(&scl_rate, i2c_rate, &div_a, &div_b);
+ if (err)
+ return err;
+
+ control = readl(&i2c->regs->control);
+ control &= ~(CDNS_I2C_CONTROL_DIV_B_MASK | CDNS_I2C_CONTROL_DIV_A_MASK);
+ control |= (div_b << CDNS_I2C_CONTROL_DIV_B_SHIFT) |
+ (div_a << CDNS_I2C_CONTROL_DIV_A_SHIFT);
+ writel(control, &i2c->regs->control);
+
+ return err;
+}
+
+static int cdns_i2c_read(struct cdns_i2c *i2c, uchar chip, uchar *buf,
+ uint buf_len)
+{
+ struct i2c_regs *regs = i2c->regs;
+ u32 control;
+ int err;
+
+ control = readl(&regs->control);
+ control |= CDNS_I2C_CONTROL_RW | CDNS_I2C_CONTROL_CLR_FIFO;
+ if (i2c->bus_hold_flag || (buf_len > CDNS_I2C_FIFO_DEPTH))
+ control |= CDNS_I2C_CONTROL_HOLD;
+ writel(control, &regs->control);
+
+ do {
+ uint bytes_to_receive;
+ u32 isr_status;
+ u64 start_time;
+
+ isr_status = readl(&regs->interrupt_status);
+ writel(isr_status, &regs->interrupt_status);
+
+ if (buf_len > CDNS_I2C_TRANSFER_SIZE)
+ bytes_to_receive = CDNS_I2C_TRANSFER_SIZE;
+ else
+ bytes_to_receive = buf_len;
+
+ buf_len -= bytes_to_receive;
+
+ writel(bytes_to_receive, &regs->transfer_size);
+ writel(chip & CDNS_I2C_ADDRESS_MASK, &regs->address);
+
+ start_time = get_time_ns();
+ while (bytes_to_receive) {
+ err = cdns_i2c_hw_error(i2c);
+ if (err)
+ goto i2c_exit;
+
+ if (is_timeout(start_time,
+ (I2C_TIMEOUT_US * USECOND))) {
+ err = -ETIMEDOUT;
+ goto i2c_exit;
+ }
+
+ if (readl(&regs->status) & CDNS_I2C_STATUS_RXDV) {
+ *buf++ = readl(&regs->data);
+ bytes_to_receive--;
+ }
+ }
+
+ } while (buf_len);
+
+ err = cdns_i2c_wait_for_completion(i2c);
+
+i2c_exit:
+ if (!i2c->bus_hold_flag)
+ cdns_i2c_clear_hold_flag(i2c);
+
+ return err;
+}
+
+static int cdns_i2c_write(struct cdns_i2c *i2c, uchar chip, uchar *buf,
+ uint buf_len)
+{
+ struct i2c_regs *regs = i2c->regs;
+ u32 control;
+ u32 isr_status;
+ bool start_transfer;
+ int err;
+
+ control = readl(&regs->control);
+ control &= ~CDNS_I2C_CONTROL_RW;
+ control |= CDNS_I2C_CONTROL_CLR_FIFO;
+ if (i2c->bus_hold_flag || (buf_len > CDNS_I2C_FIFO_DEPTH))
+ control |= CDNS_I2C_CONTROL_HOLD;
+ writel(control, &regs->control);
+
+ isr_status = readl(&regs->interrupt_status);
+ writel(isr_status, &regs->interrupt_status);
+
+ start_transfer = true;
+ do {
+ uint bytes_to_send;
+
+ bytes_to_send =
+ CDNS_I2C_FIFO_DEPTH - readl(&regs->transfer_size);
+
+ if (buf_len < bytes_to_send)
+ bytes_to_send = buf_len;
+
+ buf_len -= bytes_to_send;
+
+ while (bytes_to_send--)
+ writel(*buf++, &regs->data);
+
+ if (start_transfer) {
+ writel(chip & CDNS_I2C_ADDRESS_MASK, &regs->address);
+ start_transfer = false;
+ }
+
+ err = cdns_i2c_wait_for_completion(i2c);
+ if (err)
+ goto i2c_exit;
+
+ } while (buf_len);
+
+i2c_exit:
+ if (!i2c->bus_hold_flag)
+ cdns_i2c_clear_hold_flag(i2c);
+
+ return err;
+}
+
+static int cdns_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct cdns_i2c *i2c = container_of(adapter, struct cdns_i2c, adapter);
+ int i;
+ int err;
+
+ if (cdns_i2c_is_busy(i2c))
+ return -EBUSY;
+
+ for (i = 0; i < nmsgs; i++) {
+ i2c->bus_hold_flag = i < (nmsgs - 1);
+
+ if (msg->flags & I2C_M_RD) {
+ err = cdns_i2c_read(i2c, msg->addr, msg->buf, msg->len);
+ } else {
+ err = cdns_i2c_write(i2c, msg->addr, msg->buf,
+ msg->len);
+ }
+
+ if (err)
+ return err;
+
+ msg++;
+ }
+
+ return nmsgs;
+}
+
+static int cdns_i2c_probe(struct device_d *dev)
+{
+ struct device_node *np = dev->device_node;
+ struct resource *iores;
+ struct cdns_i2c *i2c;
+ u32 bitrate;
+ int err;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ i2c = xzalloc(sizeof(*i2c));
+
+ dev->priv = i2c;
+ i2c->regs = IOMEM(iores->start);
+
+ i2c->clk = clk_get(dev, NULL);
+ if (IS_ERR(i2c->clk))
+ return PTR_ERR(i2c->clk);
+
+ err = clk_enable(i2c->clk);
+ if (err)
+ return err;
+
+ i2c->adapter.master_xfer = cdns_i2c_xfer;
+ i2c->adapter.nr = dev->id;
+ i2c->adapter.dev.parent = dev;
+ i2c->adapter.dev.device_node = np;
+
+ cdns_i2c_reset_hardware(i2c);
+
+ bitrate = 100000;
+ of_property_read_u32(np, "clock-frequency", &bitrate);
+
+ err = cdns_i2c_set_clk(i2c, bitrate);
+ if (err)
+ return err;
+
+ cdns_i2c_setup_master(i2c);
+
+ return i2c_add_numbered_adapter(&i2c->adapter);
+}
+
+static const struct of_device_id cdns_i2c_match[] = {
+ { .compatible = "cdns,i2c-r1p14" },
+ {},
+};
+
+static struct driver_d cdns_i2c_driver = {
+ .name = "cdns-i2c",
+ .of_compatible = cdns_i2c_match,
+ .probe = cdns_i2c_probe,
+};
+coredevice_platform_driver(cdns_i2c_driver);
diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
index 4990735a4b..ca33905335 100644
--- a/drivers/i2c/busses/i2c-rockchip.c
+++ b/drivers/i2c/busses/i2c-rockchip.c
@@ -375,15 +375,17 @@ i2c_exit:
return err;
}
-static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
int nmsgs)
{
struct rk_i2c *i2c = to_rk_i2c(adapter);
struct device_d *dev = &adapter->dev;
- int ret;
+ int i, ret = 0;
dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs);
- for (; nmsgs > 0; nmsgs--, msg++) {
+ for (i = 0; i < nmsgs; i++) {
+ struct i2c_msg *msg = &msgs[i];
+
dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
@@ -395,14 +397,15 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
if (ret) {
dev_dbg(dev, "i2c_write: error sending: %pe\n",
ERR_PTR(ret));
- return -EREMOTEIO;
+ ret = -EREMOTEIO;
+ break;
}
}
rk_i2c_send_stop_bit(i2c);
rk_i2c_disable(i2c);
- return 0;
+ return ret < 0 ? ret : nmsgs;
}
static int rk_i2c_probe(struct device_d *dev)
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index 445703ecd8..2d86d86334 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -83,7 +83,6 @@ struct rockchip_combphy_priv {
struct regmap *pipe_grf;
struct regmap *phy_grf;
struct phy *phy;
- struct reset_control *apb_rst;
struct reset_control *phy_rst;
const struct rockchip_combphy_cfg *cfg;
};
@@ -317,17 +316,7 @@ static int rockchip_combphy_parse_dt(struct device_d *dev,
param_write(priv->pipe_grf, &phy_cfg->grfcfg->pipe_sgmii_mac_sel,
true);
- priv->apb_rst = reset_control_get(dev, "combphy-apb");
- if (IS_ERR(priv->apb_rst)) {
- ret = PTR_ERR(priv->apb_rst);
-
- if (ret != -EPROBE_DEFER)
- dev_warn(dev, "failed to get apb reset\n");
-
- return ret;
- }
-
- priv->phy_rst = reset_control_get(dev, "combphy");
+ priv->phy_rst = reset_control_get(dev, NULL);
if (IS_ERR(priv->phy_rst)) {
ret = PTR_ERR(priv->phy_rst);
@@ -579,9 +568,9 @@ static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = {
};
static const struct clk_bulk_data rk3568_clks[] = {
- { .id = "refclk" },
- { .id = "apbclk" },
- { .id = "pipe_clk" },
+ { .id = "ref" },
+ { .id = "apb" },
+ { .id = "pipe" },
};
static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = {
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index 464ae1aebc..f93a89ab95 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -366,11 +366,6 @@ static __maybe_unused struct ns16550_drvdata jz_drvdata = {
.init_port = ns16550_jz_init_port,
};
-static __maybe_unused struct ns16550_drvdata tegra_drvdata = {
- .init_port = ns16550_serial_init_port,
- .linux_console_name = "ttyS",
-};
-
static __maybe_unused struct ns16550_drvdata rpi_drvdata = {
.init_port = rpi_init_port,
.linux_console_name = "ttyS",
@@ -528,6 +523,9 @@ static struct of_device_id ns16550_serial_dt_ids[] = {
}, {
.compatible = "marvell,armada-38x-uart",
.data = &ns16550_drvdata,
+ }, {
+ .compatible = "nvidia,tegra20-uart",
+ .data = &ns16550_drvdata,
},
#if IS_ENABLED(CONFIG_ARCH_OMAP)
{
@@ -541,12 +539,6 @@ static struct of_device_id ns16550_serial_dt_ids[] = {
.data = &omap_drvdata,
},
#endif
-#if IS_ENABLED(CONFIG_ARCH_TEGRA)
- {
- .compatible = "nvidia,tegra20-uart",
- .data = &tegra_drvdata,
- },
-#endif
#if IS_ENABLED(CONFIG_MACH_MIPS_XBURST)
{
.compatible = "ingenic,jz4740-uart",
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7df7561718..8935feb97b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -124,6 +124,12 @@ config SPI_NXP_FLEXSPI
This controller does not support generic SPI messages and only
supports the high-level SPI memory interface.
+config SPI_SIFIVE
+ tristate "SiFive SPI controller"
+ depends on SOC_SIFIVE || COMPILE_TEST
+ help
+ This exposes the SPI controller IP from SiFive.
+
endif
endmenu
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 64c8e2645a..3455eea869 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_DRIVER_SPI_DSPI) += dspi_spi.o
obj-$(CONFIG_SPI_ZYNQ_QSPI) += zynq_qspi.o
obj-$(CONFIG_SPI_NXP_FLEXSPI) += spi-nxp-fspi.o
obj-$(CONFIG_DRIVER_SPI_STM32) += stm32_spi.o
+obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o
diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
new file mode 100644
index 0000000000..713bcc0c3b
--- /dev/null
+++ b/drivers/spi/spi-sifive.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 SiFive, Inc.
+ * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
+ *
+ * SiFive SPI controller driver (master mode only)
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <driver.h>
+#include <init.h>
+#include <errno.h>
+#include <linux/reset.h>
+#include <spi/spi.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/bitops.h>
+#include <clock.h>
+#include <gpio.h>
+#include <of_gpio.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <linux/log2.h>
+
+#define SIFIVE_SPI_MAX_CS 32
+
+#define SIFIVE_SPI_DEFAULT_DEPTH 8
+#define SIFIVE_SPI_DEFAULT_BITS 8
+
+/* register offsets */
+#define SIFIVE_SPI_REG_SCKDIV 0x00 /* Serial clock divisor */
+#define SIFIVE_SPI_REG_SCKMODE 0x04 /* Serial clock mode */
+#define SIFIVE_SPI_REG_CSID 0x10 /* Chip select ID */
+#define SIFIVE_SPI_REG_CSDEF 0x14 /* Chip select default */
+#define SIFIVE_SPI_REG_CSMODE 0x18 /* Chip select mode */
+#define SIFIVE_SPI_REG_DELAY0 0x28 /* Delay control 0 */
+#define SIFIVE_SPI_REG_DELAY1 0x2c /* Delay control 1 */
+#define SIFIVE_SPI_REG_FMT 0x40 /* Frame format */
+#define SIFIVE_SPI_REG_TXDATA 0x48 /* Tx FIFO data */
+#define SIFIVE_SPI_REG_RXDATA 0x4c /* Rx FIFO data */
+#define SIFIVE_SPI_REG_TXMARK 0x50 /* Tx FIFO watermark */
+#define SIFIVE_SPI_REG_RXMARK 0x54 /* Rx FIFO watermark */
+#define SIFIVE_SPI_REG_FCTRL 0x60 /* SPI flash interface control */
+#define SIFIVE_SPI_REG_FFMT 0x64 /* SPI flash instruction format */
+#define SIFIVE_SPI_REG_IE 0x70 /* Interrupt Enable Register */
+#define SIFIVE_SPI_REG_IP 0x74 /* Interrupt Pendings Register */
+
+/* sckdiv bits */
+#define SIFIVE_SPI_SCKDIV_DIV_MASK 0xfffU
+
+/* sckmode bits */
+#define SIFIVE_SPI_SCKMODE_PHA BIT(0)
+#define SIFIVE_SPI_SCKMODE_POL BIT(1)
+#define SIFIVE_SPI_SCKMODE_MODE_MASK (SIFIVE_SPI_SCKMODE_PHA | \
+ SIFIVE_SPI_SCKMODE_POL)
+
+/* csmode bits */
+#define SIFIVE_SPI_CSMODE_MODE_AUTO 0U
+#define SIFIVE_SPI_CSMODE_MODE_HOLD 2U
+#define SIFIVE_SPI_CSMODE_MODE_OFF 3U
+
+/* delay0 bits */
+#define SIFIVE_SPI_DELAY0_CSSCK(x) ((u32)(x))
+#define SIFIVE_SPI_DELAY0_CSSCK_MASK 0xffU
+#define SIFIVE_SPI_DELAY0_SCKCS(x) ((u32)(x) << 16)
+#define SIFIVE_SPI_DELAY0_SCKCS_MASK (0xffU << 16)
+
+/* delay1 bits */
+#define SIFIVE_SPI_DELAY1_INTERCS(x) ((u32)(x))
+#define SIFIVE_SPI_DELAY1_INTERCS_MASK 0xffU
+#define SIFIVE_SPI_DELAY1_INTERXFR(x) ((u32)(x) << 16)
+#define SIFIVE_SPI_DELAY1_INTERXFR_MASK (0xffU << 16)
+
+/* fmt bits */
+#define SIFIVE_SPI_FMT_PROTO_SINGLE 0U
+#define SIFIVE_SPI_FMT_PROTO_DUAL 1U
+#define SIFIVE_SPI_FMT_PROTO_QUAD 2U
+#define SIFIVE_SPI_FMT_PROTO_MASK 3U
+#define SIFIVE_SPI_FMT_ENDIAN BIT(2)
+#define SIFIVE_SPI_FMT_DIR BIT(3)
+#define SIFIVE_SPI_FMT_LEN(x) ((u32)(x) << 16)
+#define SIFIVE_SPI_FMT_LEN_MASK (0xfU << 16)
+
+/* txdata bits */
+#define SIFIVE_SPI_TXDATA_DATA_MASK 0xffU
+#define SIFIVE_SPI_TXDATA_FULL BIT(31)
+
+/* rxdata bits */
+#define SIFIVE_SPI_RXDATA_DATA_MASK 0xffU
+#define SIFIVE_SPI_RXDATA_EMPTY BIT(31)
+
+/* ie and ip bits */
+#define SIFIVE_SPI_IP_TXWM BIT(0)
+#define SIFIVE_SPI_IP_RXWM BIT(1)
+
+/* format protocol */
+#define SIFIVE_SPI_PROTO_QUAD 4 /* 4 lines I/O protocol transfer */
+#define SIFIVE_SPI_PROTO_DUAL 2 /* 2 lines I/O protocol transfer */
+#define SIFIVE_SPI_PROTO_SINGLE 1 /* 1 line I/O protocol transfer */
+
+#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */
+#define SPI_XFER_END 0x02 /* Deassert CS after transfer */
+
+struct sifive_spi {
+ struct spi_controller ctlr;
+ void __iomem *regs; /* base address of the registers */
+ u32 fifo_depth;
+ u32 bits_per_word;
+ u32 cs_inactive; /* Level of the CS pins when inactive*/
+ u32 freq;
+ u8 fmt_proto;
+};
+
+static inline struct sifive_spi *to_sifive_spi(struct spi_controller *ctlr)
+{
+ return container_of(ctlr, struct sifive_spi, ctlr);
+}
+
+static void sifive_spi_prep_device(struct sifive_spi *spi,
+ struct spi_device *spi_dev)
+{
+ /* Update the chip select polarity */
+ if (spi_dev->mode & SPI_CS_HIGH)
+ spi->cs_inactive &= ~BIT(spi_dev->chip_select);
+ else
+ spi->cs_inactive |= BIT(spi_dev->chip_select);
+ writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
+
+ /* Select the correct device */
+ writel(spi_dev->chip_select, spi->regs + SIFIVE_SPI_REG_CSID);
+}
+
+static void sifive_spi_set_cs(struct sifive_spi *spi,
+ struct spi_device *spi_dev)
+{
+ u32 cs_mode = SIFIVE_SPI_CSMODE_MODE_HOLD;
+
+ if (spi_dev->mode & SPI_CS_HIGH)
+ cs_mode = SIFIVE_SPI_CSMODE_MODE_AUTO;
+
+ writel(cs_mode, spi->regs + SIFIVE_SPI_REG_CSMODE);
+}
+
+static void sifive_spi_clear_cs(struct sifive_spi *spi)
+{
+ writel(SIFIVE_SPI_CSMODE_MODE_AUTO, spi->regs + SIFIVE_SPI_REG_CSMODE);
+}
+
+static void sifive_spi_prep_transfer(struct sifive_spi *spi,
+ struct spi_device *spi_dev,
+ u8 *rx_ptr)
+{
+ u32 cr;
+
+ /* Modify the SPI protocol mode */
+ cr = readl(spi->regs + SIFIVE_SPI_REG_FMT);
+
+ /* Bits per word ? */
+ cr &= ~SIFIVE_SPI_FMT_LEN_MASK;
+ cr |= SIFIVE_SPI_FMT_LEN(spi->bits_per_word);
+
+ /* LSB first? */
+ cr &= ~SIFIVE_SPI_FMT_ENDIAN;
+ if (spi_dev->mode & SPI_LSB_FIRST)
+ cr |= SIFIVE_SPI_FMT_ENDIAN;
+
+ /* Number of wires ? */
+ cr &= ~SIFIVE_SPI_FMT_PROTO_MASK;
+ switch (spi->fmt_proto) {
+ case SIFIVE_SPI_PROTO_QUAD:
+ cr |= SIFIVE_SPI_FMT_PROTO_QUAD;
+ break;
+ case SIFIVE_SPI_PROTO_DUAL:
+ cr |= SIFIVE_SPI_FMT_PROTO_DUAL;
+ break;
+ default:
+ cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
+ break;
+ }
+
+ /* SPI direction in/out ? */
+ cr &= ~SIFIVE_SPI_FMT_DIR;
+ if (!rx_ptr)
+ cr |= SIFIVE_SPI_FMT_DIR;
+
+ writel(cr, spi->regs + SIFIVE_SPI_REG_FMT);
+}
+
+static void sifive_spi_rx(struct sifive_spi *spi, u8 *rx_ptr)
+{
+ u32 data;
+
+ do {
+ data = readl(spi->regs + SIFIVE_SPI_REG_RXDATA);
+ } while (data & SIFIVE_SPI_RXDATA_EMPTY);
+
+ if (rx_ptr)
+ *rx_ptr = data & SIFIVE_SPI_RXDATA_DATA_MASK;
+}
+
+static void sifive_spi_tx(struct sifive_spi *spi, const u8 *tx_ptr)
+{
+ u32 data;
+ u8 tx_data = (tx_ptr) ? *tx_ptr & SIFIVE_SPI_TXDATA_DATA_MASK :
+ SIFIVE_SPI_TXDATA_DATA_MASK;
+
+ do {
+ data = readl(spi->regs + SIFIVE_SPI_REG_TXDATA);
+ } while (data & SIFIVE_SPI_TXDATA_FULL);
+
+ writel(tx_data, spi->regs + SIFIVE_SPI_REG_TXDATA);
+}
+
+static int sifive_spi_wait(struct sifive_spi *spi, u32 mask)
+{
+ u32 val;
+
+ return readl_poll_timeout(spi->regs + SIFIVE_SPI_REG_IP, val,
+ (val & mask) == mask, 100 * USEC_PER_MSEC);
+}
+
+static int sifive_spi_transfer_one(struct spi_device *spi_dev, unsigned int nbytes,
+ const void *dout, void *din)
+{
+ struct sifive_spi *spi = to_sifive_spi(spi_dev->controller);
+ const u8 *tx_ptr = dout;
+ u8 *rx_ptr = din;
+ int ret;
+
+ sifive_spi_prep_transfer(spi, spi_dev, rx_ptr);
+
+ while (nbytes) {
+ unsigned int n_words = min(nbytes, spi->fifo_depth);
+ unsigned int tx_words, rx_words;
+
+ /* Enqueue n_words for transmission */
+ for (tx_words = 0; tx_words < n_words; tx_words++) {
+ if (!tx_ptr)
+ sifive_spi_tx(spi, NULL);
+ else
+ sifive_spi_tx(spi, tx_ptr++);
+ }
+
+ if (rx_ptr) {
+ /* Wait for transmission + reception to complete */
+ writel(n_words - 1, spi->regs + SIFIVE_SPI_REG_RXMARK);
+ ret = sifive_spi_wait(spi, SIFIVE_SPI_IP_RXWM);
+ if (ret)
+ return ret;
+
+ /* Read out all the data from the RX FIFO */
+ for (rx_words = 0; rx_words < n_words; rx_words++)
+ sifive_spi_rx(spi, rx_ptr++);
+ } else {
+ /* Wait for transmission to complete */
+ ret = sifive_spi_wait(spi, SIFIVE_SPI_IP_TXWM);
+ if (ret)
+ return ret;
+ }
+
+ nbytes -= n_words;
+ }
+
+ return 0;
+}
+
+static int sifive_spi_transfer(struct spi_device *spi_dev, struct spi_message *msg)
+{
+ struct spi_controller *ctlr = spi_dev->controller;
+ struct sifive_spi *spi = to_sifive_spi(ctlr);
+ struct spi_transfer *t;
+ int ret = 0;
+
+ if (list_empty(&msg->transfers))
+ return 0;
+
+ msg->actual_length = 0;
+
+ sifive_spi_prep_device(spi, spi_dev);
+ sifive_spi_set_cs(spi, spi_dev);
+
+ dev_dbg(ctlr->dev, "transfer start actual_length=%i\n", msg->actual_length);
+ list_for_each_entry(t, &msg->transfers, transfer_list) {
+ dev_dbg(ctlr->dev, " xfer %p: len %u tx %p rx %p\n",
+ t, t->len, t->tx_buf, t->rx_buf);
+
+ ret = sifive_spi_transfer_one(spi_dev, t->len,
+ t->tx_buf, t->rx_buf);
+ if (ret < 0)
+ goto out;
+ msg->actual_length += t->len;
+ }
+ dev_dbg(ctlr->dev, "transfer done actual_length=%i\n", msg->actual_length);
+
+out:
+ sifive_spi_clear_cs(spi);
+ return ret;
+}
+
+static int sifive_spi_exec_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct spi_device *spi_dev = mem->spi;
+ struct device_d *dev = &spi_dev->dev;
+ struct sifive_spi *spi = spi_controller_get_devdata(spi_dev->controller);
+ u8 opcode = op->cmd.opcode;
+ int ret;
+
+ spi->fmt_proto = op->cmd.buswidth;
+
+ sifive_spi_prep_device(spi, spi_dev);
+ sifive_spi_set_cs(spi, spi_dev);
+
+ /* send the opcode */
+ ret = sifive_spi_transfer_one(spi_dev, 1, &opcode, NULL);
+ if (ret < 0) {
+ dev_err(dev, "failed to xfer opcode\n");
+ goto out;
+ }
+
+ if (!op->addr.nbytes && !op->data.nbytes)
+ goto out;
+
+ /* send the addr + dummy */
+ if (op->addr.nbytes) {
+ int i, op_len = op->addr.nbytes + op->dummy.nbytes;
+ u8 *op_buf;
+
+ op_buf = malloc(op_len);
+ if (!op_buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* fill address */
+ for (i = 0; i < op->addr.nbytes; i++)
+ op_buf[i] = op->addr.val >>
+ (8 * (op->addr.nbytes - i - 1));
+
+ /* fill dummy */
+ memset(op_buf + op->addr.nbytes, 0xff, op->dummy.nbytes);
+
+ spi->fmt_proto = op->addr.buswidth;
+
+ ret = sifive_spi_transfer_one(spi_dev, op_len, op_buf, NULL);
+ free(op_buf);
+ if (ret < 0) {
+ dev_err(dev, "failed to xfer addr + dummy\n");
+ goto out;
+ }
+ }
+
+ /* send/received the data */
+ if (op->data.nbytes) {
+ const void *tx_buf = NULL;
+ void *rx_buf = NULL;
+
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ rx_buf = op->data.buf.in;
+ else
+ tx_buf = op->data.buf.out;
+
+ spi->fmt_proto = op->data.buswidth;
+
+ ret = sifive_spi_transfer_one(spi_dev, op->data.nbytes,
+ tx_buf, rx_buf);
+ if (ret) {
+ dev_err(dev, "failed to xfer data\n");
+ goto out;
+ }
+ }
+
+out:
+ sifive_spi_clear_cs(spi);
+ return ret;
+}
+
+static void sifive_spi_set_speed(struct sifive_spi *spi, uint speed)
+{
+ u32 scale;
+
+ if (speed > spi->freq)
+ speed = spi->freq;
+
+ /* Cofigure max speed */
+ scale = (DIV_ROUND_UP(spi->freq >> 1, speed) - 1)
+ & SIFIVE_SPI_SCKDIV_DIV_MASK;
+ writel(scale, spi->regs + SIFIVE_SPI_REG_SCKDIV);
+}
+
+static void sifive_spi_set_mode(struct sifive_spi *spi, uint mode)
+{
+ u32 cr;
+
+ /* Switch clock mode bits */
+ cr = readl(spi->regs + SIFIVE_SPI_REG_SCKMODE) &
+ ~SIFIVE_SPI_SCKMODE_MODE_MASK;
+ if (mode & SPI_CPHA)
+ cr |= SIFIVE_SPI_SCKMODE_PHA;
+ if (mode & SPI_CPOL)
+ cr |= SIFIVE_SPI_SCKMODE_POL;
+
+ writel(cr, spi->regs + SIFIVE_SPI_REG_SCKMODE);
+}
+
+static int sifive_spi_setup(struct spi_device *spi_dev)
+{
+ struct sifive_spi *spi = to_sifive_spi(spi_dev->controller);
+
+ sifive_spi_set_mode(spi, spi_dev->mode);
+ sifive_spi_set_speed(spi, spi_dev->max_speed_hz);
+
+ return 0;
+}
+
+static void sifive_spi_init_hw(struct sifive_spi *spi)
+{
+ struct device_d *dev = spi->ctlr.dev;
+ u32 cs_bits;
+
+ /* probe the number of CS lines */
+ spi->cs_inactive = readl(spi->regs + SIFIVE_SPI_REG_CSDEF);
+ writel(0xffffffffU, spi->regs + SIFIVE_SPI_REG_CSDEF);
+ cs_bits = readl(spi->regs + SIFIVE_SPI_REG_CSDEF);
+ writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
+ if (!cs_bits) {
+ dev_warn(dev, "Could not auto probe CS lines\n");
+ return;
+ }
+
+ spi->ctlr.num_chipselect = ilog2(cs_bits) + 1;
+ if (spi->ctlr.num_chipselect > SIFIVE_SPI_MAX_CS) {
+ dev_warn(dev, "Invalid number of spi slaves\n");
+ return;
+ }
+
+ /* Watermark interrupts are disabled by default */
+ writel(0, spi->regs + SIFIVE_SPI_REG_IE);
+
+ /* Default watermark FIFO threshold values */
+ writel(1, spi->regs + SIFIVE_SPI_REG_TXMARK);
+ writel(0, spi->regs + SIFIVE_SPI_REG_RXMARK);
+
+ /* Set CS/SCK Delays and Inactive Time to defaults */
+ writel(SIFIVE_SPI_DELAY0_CSSCK(1) | SIFIVE_SPI_DELAY0_SCKCS(1),
+ spi->regs + SIFIVE_SPI_REG_DELAY0);
+ writel(SIFIVE_SPI_DELAY1_INTERCS(1) | SIFIVE_SPI_DELAY1_INTERXFR(0),
+ spi->regs + SIFIVE_SPI_REG_DELAY1);
+
+ /* Exit specialized memory-mapped SPI flash mode */
+ writel(0, spi->regs + SIFIVE_SPI_REG_FCTRL);
+}
+
+static const struct spi_controller_mem_ops sifive_spi_mem_ops = {
+ .exec_op = sifive_spi_exec_op,
+};
+
+static void sifive_spi_dt_probe(struct sifive_spi *spi)
+{
+ struct device_node *node = spi->ctlr.dev->device_node;
+
+ spi->fifo_depth = SIFIVE_SPI_DEFAULT_DEPTH;
+ of_property_read_u32(node, "sifive,fifo-depth", &spi->fifo_depth);
+
+ spi->bits_per_word = SIFIVE_SPI_DEFAULT_BITS;
+ of_property_read_u32(node, "sifive,max-bits-per-word", &spi->bits_per_word);
+}
+
+static int sifive_spi_probe(struct device_d *dev)
+{
+ struct sifive_spi *spi;
+ struct resource *iores;
+ struct spi_controller *ctlr;
+ struct clk *clkdev;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ spi = xzalloc(sizeof(*spi));
+
+ spi->regs = IOMEM(iores->start);
+ if (!spi->regs)
+ return -ENODEV;
+
+ ctlr = &spi->ctlr;
+ ctlr->dev = dev;
+
+ ctlr->setup = sifive_spi_setup;
+ ctlr->transfer = sifive_spi_transfer;
+ ctlr->mem_ops = &sifive_spi_mem_ops;
+
+ ctlr->bus_num = -1;
+
+ spi_controller_set_devdata(ctlr, spi);
+
+ sifive_spi_dt_probe(spi);
+
+ clkdev = clk_get(dev, NULL);
+ if (IS_ERR(clkdev))
+ return PTR_ERR(clkdev);
+
+ spi->freq = clk_get_rate(clkdev);
+
+ /* init the sifive spi hw */
+ sifive_spi_init_hw(spi);
+
+ return spi_register_master(ctlr);
+}
+
+static const struct of_device_id sifive_spi_ids[] = {
+ { .compatible = "sifive,spi0" },
+ { /* sentinel */ }
+};
+
+static struct driver_d sifive_spi_driver = {
+ .name = "sifive_spi",
+ .probe = sifive_spi_probe,
+ .of_compatible = sifive_spi_ids,
+};
+coredevice_platform_driver(sifive_spi_driver);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fd0ec754e0..30aaef90ac 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -23,6 +23,11 @@
#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
+struct dwc3_match_data {
+ const struct clk_bulk_data *clks;
+ const int num_clks;
+};
+
/**
* dwc3_get_dr_mode - Validates and sets dr_mode
* @dwc: pointer to our context structure
@@ -326,12 +331,6 @@ err0:
return ret;
}
-static const struct clk_bulk_data dwc3_core_clks[] = {
- { .id = "ref" },
- { .id = "bus_early" },
- { .id = "suspend" },
-};
-
/*
* dwc3_frame_length_adjustment - Adjusts frame length if required
* @dwc3: Pointer to our controller context structure
@@ -1098,20 +1097,23 @@ static void dwc3_coresoft_reset(struct dwc3 *dwc)
static int dwc3_probe(struct device_d *dev)
{
+ const struct dwc3_match_data *match;
struct dwc3 *dwc;
int ret;
dwc = xzalloc(sizeof(*dwc));
dev->priv = dwc;
- dwc->clks = xmemdup(dwc3_core_clks, sizeof(dwc3_core_clks));
+ match = device_get_match_data(dev);
+ dwc->clks = xmemdup(match->clks, match->num_clks *
+ sizeof(struct clk_bulk_data));
dwc->dev = dev;
dwc->regs = dev_get_mem_region(dwc->dev, 0) + DWC3_GLOBALS_REGS_START;
dwc3_get_properties(dwc);
if (dev->device_node) {
- dwc->num_clks = ARRAY_SIZE(dwc3_core_clks);
+ dwc->num_clks = match->num_clks;
if (of_find_property(dev->device_node, "clocks", NULL)) {
ret = clk_bulk_get(dev, dwc->num_clks, dwc->clks);
@@ -1176,12 +1178,40 @@ static void dwc3_remove(struct device_d *dev)
clk_bulk_put(dwc->num_clks, dwc->clks);
}
+static const struct clk_bulk_data dwc3_core_clks[] = {
+ { .id = "ref" },
+ { .id = "bus_early" },
+ { .id = "suspend" },
+};
+
+static const struct dwc3_match_data dwc3_default = {
+ .clks = dwc3_core_clks,
+ .num_clks = ARRAY_SIZE(dwc3_core_clks),
+};
+
+static const struct clk_bulk_data dwc3_core_clks_rk3568[] = {
+ { .id = "ref_clk" },
+ { .id = "bus_clk" },
+ { .id = "suspend_clk" },
+};
+
+static const struct dwc3_match_data dwc3_rk3568 = {
+ .clks = dwc3_core_clks_rk3568,
+ .num_clks = ARRAY_SIZE(dwc3_core_clks_rk3568),
+};
+
static const struct of_device_id of_dwc3_match[] = {
{
- .compatible = "snps,dwc3"
+ .compatible = "snps,dwc3",
+ .data = &dwc3_default,
+ },
+ {
+ .compatible = "synopsys,dwc3",
+ .data = &dwc3_default,
},
{
- .compatible = "synopsys,dwc3"
+ .compatible = "rockchip,rk3568-dwc3",
+ .data = &dwc3_rk3568,
},
{ },
};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index dcdc6c2135..a20b7bbee9 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -75,7 +75,7 @@ config DRIVER_VIDEO_S3C24XX
config DRIVER_VIDEO_OMAP
bool "OMAP framebuffer driver"
- depends on ARCH_OMAP4
+ depends on ARCH_OMAP4 || COMPILE_TEST
help
Add support for OMAP Display Controller. Currently this
driver only supports OMAP4 SoCs in DISPC parallel mode on
diff --git a/drivers/video/omap.c b/drivers/video/omap.c
index 62c51a1dfc..ca41ab36fc 100644
--- a/drivers/video/omap.c
+++ b/drivers/video/omap.c
@@ -20,8 +20,7 @@
#include <clock.h>
#include <linux/err.h>
-#include <mach/omap4-silicon.h>
-#include <mach/omap-fb.h>
+#include <video/omap-fb.h>
#include <mmu.h>