diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2017-03-13 08:16:44 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2017-03-13 08:16:44 +0100 |
commit | 6134116686ea7ecd3e29db3ab40e4eac837680c3 (patch) | |
tree | a04f202006c9f11d1fe53ecb945166e3022bae6b /drivers | |
parent | e0093dcf236cdc1d4faef95189c9376ef6610ae7 (diff) | |
parent | 836b99c81b9f17414cbbbfdf1c4d92acfc7106ff (diff) | |
download | barebox-6134116686ea7ecd3e29db3ab40e4eac837680c3.tar.gz barebox-6134116686ea7ecd3e29db3ab40e4eac837680c3.tar.xz |
Merge branch 'for-next/mvebu'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/Kconfig | 5 | ||||
-rw-r--r-- | drivers/ata/Makefile | 1 | ||||
-rw-r--r-- | drivers/ata/sata_mv.c | 126 | ||||
-rw-r--r-- | drivers/bus/mvebu-mbus.c | 22 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 41 |
5 files changed, 171 insertions, 24 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 7850e4a9c9..0234c66c8e 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -42,6 +42,11 @@ config DISK_AHCI_IMX depends on DISK_AHCI bool "i.MX AHCI support" +config DISK_SATA_MV + depends on ARCH_MVEBU + select DISK_IDE_SFF + bool "Marvell SATA support" + comment "interface types" config DISK_INTF_PLATFORM_IDE diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index c444c4d196..6b83ae2ef5 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_DISK_IDE_SFF) += ide-sff.o obj-$(CONFIG_DISK_ATA) += disk_ata_drive.o obj-$(CONFIG_DISK_AHCI) += ahci.o obj-$(CONFIG_DISK_AHCI_IMX) += sata-imx.o +obj-$(CONFIG_DISK_SATA_MV) += sata_mv.o # interface types diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c new file mode 100644 index 0000000000..22b29d08a5 --- /dev/null +++ b/drivers/ata/sata_mv.c @@ -0,0 +1,126 @@ +#include <common.h> +#include <clock.h> +#include <driver.h> +#include <init.h> +#include <ata_drive.h> + +#include <asm/io.h> + +/* This can/should be moved to a more generic place */ +static void ata_ioports_init(struct ata_ioports *io, + void *base_data, void *base_reg, void *base_alt, + unsigned stride) +{ + /* io->cmd_addr is unused */; + io->data_addr = base_data; + io->error_addr = base_reg + 1 * stride; + /* io->feature_addr is unused */ + io->nsect_addr = base_reg + 2 * stride; + io->lbal_addr = base_reg + 3 * stride; + io->lbam_addr = base_reg + 4 * stride; + io->lbah_addr = base_reg + 5 * stride; + io->device_addr = base_reg + 6 * stride; + io->status_addr = base_reg + 7 * stride; + io->command_addr = base_reg + 7 * stride; + /* io->altstatus_addr is unused */ + + if (base_alt) + io->ctl_addr = base_alt; + else + io->ctl_addr = io->status_addr; + + /* io->alt_dev_addr is unused */ +} + +#define REG_WINDOW_CONTROL(n) ((n) * 0x10 + 0x30) +#define REG_WINDOW_BASE(n) ((n) * 0x10 + 0x34) + +#define REG_EDMA_COMMAND(n) ((n) * 0x2000 + 0x2028) +#define REG_EDMA_COMMAND__EATARST 0x00000004 + +#define REG_ATA_BASE 0x2100 +#define REG_SSTATUS(n) ((n) * 0x2000 + 0x2300) +#define REG_SCONTROL(n) ((n) * 0x2000 + 0x2308) +#define REG_SCONTROL__DET 0x0000000f +#define REG_SCONTROL__DET__INIT 0x00000001 +#define REG_SCONTROL__DET__PHYOK 0x00000002 +#define REG_SCONTROL__IPM 0x00000f00 +#define REG_SCONTROL__IPM__PARTIAL 0x00000100 +#define REG_SCONTROL__IPM__SLUMBER 0x00000200 + +static int mv_sata_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base; + struct ide_port *ide; + u32 scontrol; + int ret, i; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) { + dev_err(dev, "Failed to request mem resources\n"); + return PTR_ERR(iores); + } + base = IOMEM(iores->start); + + /* disable MBus windows */ + for (i = 0; i < 4; ++i) { + writel(0, base + REG_WINDOW_CONTROL(i)); + writel(0, base + REG_WINDOW_BASE(i)); + } + + /* enable first window */ + writel(0x7fff0e01, base + REG_WINDOW_CONTROL(0)); + writel(0, base + REG_WINDOW_BASE(0)); + + writel(REG_EDMA_COMMAND__EATARST, base + REG_EDMA_COMMAND(0)); + udelay(25); + writel(0x0, base + REG_EDMA_COMMAND(0)); + + scontrol = readl(base + REG_SCONTROL(0)); + scontrol &= ~(REG_SCONTROL__DET | REG_SCONTROL__IPM); + /* disable power management */ + scontrol |= REG_SCONTROL__IPM__PARTIAL | REG_SCONTROL__IPM__SLUMBER; + + /* perform interface communication initialization */ + writel(scontrol | REG_SCONTROL__DET__INIT, base + REG_SCONTROL(0)); + writel(scontrol, base + REG_SCONTROL(0)); + + ret = wait_on_timeout(10 * MSECOND, + (readl(base + REG_SSTATUS(0)) & REG_SCONTROL__DET) == (REG_SCONTROL__DET__INIT | REG_SCONTROL__DET__PHYOK)); + if (ret) { + dev_err(dev, "Failed to wait for phy (sstatus=0x%08x)\n", + readl(base + REG_SSTATUS(0))); + return ret; + } + + ide = xzalloc(sizeof(*ide)); + + ide->port.dev = dev; + + ata_ioports_init(&ide->io, base + REG_ATA_BASE, base + REG_ATA_BASE, + NULL, 4); + + dev->priv = ide; + + ret = ide_port_register(ide); + if (ret) + free(ide); + + return ret; +} + +static const struct of_device_id mv_sata_dt_ids[] = { + { + .compatible = "marvell,armada-370-sata", + }, { + /* sentinel */ + } +}; + +static struct driver_d mv_sata_driver = { + .name = "mv_sata", + .probe = mv_sata_probe, + .of_compatible = mv_sata_dt_ids, +}; +device_platform_driver(mv_sata_driver); diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index df5f7a32d3..965a221d3b 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -59,6 +59,7 @@ #include <of.h> #include <of_address.h> #include <linux/mbus.h> +#include <mach/common.h> /* DDR target is the same on all platforms */ #define TARGET_DDR 0 @@ -810,7 +811,26 @@ static int mvebu_mbus_of_fixup(struct device_node *root, void *context) return 0; } -static int mvebu_mbus_fixup_register(void) { +#define DOVE_REMAP_MC_REGS 0xf1800000 + +static int mvebu_mbus_fixup_register(void) +{ + if (IS_ENABLED(CONFIG_ARCH_ARMADA_370) || + IS_ENABLED(CONFIG_ARCH_ARMADA_XP)) + mvebu_mbus_add_range("marvell,armada-370-xp", 0xf0, 0x01, + MVEBU_REMAP_INT_REG_BASE); + + if (IS_ENABLED(CONFIG_ARCH_DOVE)) { + mvebu_mbus_add_range("marvell,dove", 0xf0, 0x01, + MVEBU_REMAP_INT_REG_BASE); + mvebu_mbus_add_range("marvell,dove", 0xf0, 0x02, + DOVE_REMAP_MC_REGS); + } + + if (IS_ENABLED(CONFIG_ARCH_KIRKWOOD)) + mvebu_mbus_add_range("marvell,kirkwood", 0xf0, 0x01, + MVEBU_REMAP_INT_REG_BASE); + return of_register_fixup(mvebu_mbus_of_fixup, NULL); } pure_initcall(mvebu_mbus_fixup_register); diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 9b9e6c953f..caece3b78e 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -270,6 +270,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) } /* FALLTHRU */ case STATUS_MAST_RD_DATA_ACK: /* 0x50 */ + udelay(2); if (status != STATUS_MAST_RD_DATA_ACK) drv_data->action = ACTION_CONTINUE; else { @@ -280,6 +281,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) if (drv_data->bytes_left == 1) drv_data->cntl_bits &= ~REG_CONTROL_ACK; + udelay(2); break; case STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */ @@ -318,6 +320,8 @@ static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data) mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); mv64xxx_write(drv_data, drv_data->cntl_bits | REG_CONTROL_START, drv_data->reg_offsets.control); + + udelay(2); } static void @@ -333,7 +337,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) mv64xxx_i2c_send_start(drv_data); if (drv_data->errata_delay) - udelay(5); + udelay(3); /* * We're never at the start of the message here, and by this @@ -349,6 +353,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) break; case ACTION_SEND_ADDR_1: + udelay(2); mv64xxx_write(drv_data, drv_data->addr1, drv_data->reg_offsets.data); mv64xxx_write(drv_data, drv_data->cntl_bits, @@ -360,9 +365,11 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->reg_offsets.data); mv64xxx_write(drv_data, drv_data->cntl_bits, drv_data->reg_offsets.control); + udelay(2); break; case ACTION_SEND_DATA: + udelay(2); mv64xxx_write(drv_data, drv_data->msg->buf[drv_data->byte_posn++], drv_data->reg_offsets.data); mv64xxx_write(drv_data, drv_data->cntl_bits, @@ -383,8 +390,9 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) mv64xxx_write(drv_data, drv_data->cntl_bits | REG_CONTROL_STOP, drv_data->reg_offsets.control); drv_data->block = false; + udelay(2); if (drv_data->errata_delay) - udelay(5); + udelay(3); break; @@ -406,26 +414,6 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) } } -static void mv64xxx_i2c_intr(struct mv64xxx_i2c_data *drv_data) -{ - u32 status; - uint64_t start; - - start = get_time_ns(); - - while (mv64xxx_read(drv_data, drv_data->reg_offsets.control) & - REG_CONTROL_IFLG) { - status = mv64xxx_read(drv_data, drv_data->reg_offsets.status); - mv64xxx_i2c_fsm(drv_data, status); - mv64xxx_i2c_do_action(drv_data); - - if (is_timeout_non_interruptible(start, 3 * SECOND)) { - drv_data->rc = -EIO; - break; - } - } -} - /* ***************************************************************************** * @@ -436,8 +424,15 @@ static void mv64xxx_i2c_intr(struct mv64xxx_i2c_data *drv_data) static void mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) { + u32 status; do { - mv64xxx_i2c_intr(drv_data); + if (mv64xxx_read(drv_data, drv_data->reg_offsets.control) & + REG_CONTROL_IFLG) { + status = mv64xxx_read(drv_data, + drv_data->reg_offsets.status); + mv64xxx_i2c_fsm(drv_data, status); + mv64xxx_i2c_do_action(drv_data); + } if (drv_data->rc) { drv_data->state = STATE_IDLE; dev_err(&drv_data->adapter.dev, "I2C bus error\n"); |