Message ID | 1418050480-27571-1-git-send-email-ian.campbell@citrix.com |
---|---|
State | Accepted |
Delegated to: | Minkyu Kang |
Headers | show |
Hi Ian, On 8 December 2014 at 07:54, Ian Campbell <ian.campbell@citrix.com> wrote: > This is based on some old patches from the chromeos-v2011.12 branch of > http://git.chromium.org/chromiumos/third_party/u-boot.git by Taylor Hutt. > Specifically: > > http://git.chromium.org/gitweb/?p=chromiumos/third_party/u-boot.git;a=commit;h=26f6c570b5deb37c52306920ae049203c68f014a > exynos: sata: on-board controller initialization > Signed-off-by: Taylor Hutt <thutt@chromium.org> > > http://git.chromium.org/gitweb/?p=chromiumos/third_party/u-boot.git;a=commit;h=d8cac5cf0b63df00d2d6ac7df814613e4b60b9d1 > exynos: sata: Add sata_initialize() interface > Signed-off-by: Taylor Hutt <thutt@chromium.org> > > http://git.chromium.org/gitweb/?p=chromiumos/third_party/u-boot.git;a=commit;h=dd32462453d6328bc5770859d1b56501f7920d7d > exynos: sata: SATA self-configuration for when SATA device is enabled > Signed-off-by: Taylor Hutt <thutt@chromium.org> Thanks for cleaning this up and submitting it. > > As well as rebasing there have been some significant changes. > > - Drop support for smdk5250, which I don't own. > - Implement support for arndale, which I do. > - Since arndale has no need to frob a GPIO on SATA init drop the associated > code. > - Initialise via the existing scsi_init hook rather than introducing > sata_initialize, associated build system and include/configs/*.h changes. > - Use set/clrbits in a bunch of places > - Add some #defines for some magic numbers. > - Use samsung_get_base_* for peripheral base addresses and structs to > access individual registers > - Lots of coding style improvements (checkpatch.pl clean) and general cleanup > > Before launching the OS reset the PHY, otherwise Linux cannot reliably > detect the disk. > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > Cc: Taylor Hutt <thutt@chromium.org> > Cc: Simon Glass <sjg@chromium.org> > --- > Lots of changes in v2: > - Rebase to latest master branch. > - use samsung_get_base_* for sata phy > - use samsung_get_base_* for sata i2c > - use samsung_get_base_* for sata axi > - Lots of Coding Style improvements > - Drop unused mmio argument to phy init > - Move code controlling phy power to power.c > - Remove unused SCLK_SATA_FREQ > - Use #defines for SATA_GENERATION<N>, less fickle than enum > - avoid non-existent BIT macro > - Use bool more consistently in a few places > - No uppercase variable names > - Use SPDX License + copyright > - Use arch_preboot_os to reset SATA controller, and do so more > thoroughly than in the previous HACK. It now appears to be reliable > in my testing. > --- > arch/arm/cpu/armv7/exynos/Makefile | 4 + > arch/arm/cpu/armv7/exynos/power.c | 23 ++ > arch/arm/cpu/armv7/exynos/sata.c | 412 +++++++++++++++++++++++++++++++ > arch/arm/cpu/armv7/exynos/soc.c | 8 + > arch/arm/include/asm/arch-exynos/cpu.h | 15 ++ > arch/arm/include/asm/arch-exynos/power.h | 4 + > arch/arm/include/asm/arch-exynos/sata.h | 13 + > arch/arm/lib/board.c | 1 + > board/samsung/arndale/arndale.c | 9 + > include/configs/arndale.h | 3 + > include/configs/exynos5-common.h | 18 ++ > 11 files changed, 510 insertions(+) > create mode 100644 arch/arm/cpu/armv7/exynos/sata.c > create mode 100644 arch/arm/include/asm/arch-exynos/sata.h > > diff --git a/arch/arm/cpu/armv7/exynos/Makefile b/arch/arm/cpu/armv7/exynos/Makefile > index e207bd6..c74a2d4 100644 > --- a/arch/arm/cpu/armv7/exynos/Makefile > +++ b/arch/arm/cpu/armv7/exynos/Makefile > @@ -7,6 +7,10 @@ > > obj-y += clock.o power.o soc.o system.o pinmux.o tzpc.o > > +ifndef CONFIG_SPL_BUILD > +obj-$(CONFIG_EXYNOS5250_AHCI) += sata.o > +endif > + > ifdef CONFIG_SPL_BUILD > obj-$(CONFIG_EXYNOS5) += clock_init_exynos5.o > obj-$(CONFIG_EXYNOS5) += dmc_common.o dmc_init_ddr3.o > diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c > index 1520d64..8f36d10 100644 > --- a/arch/arm/cpu/armv7/exynos/power.c > +++ b/arch/arm/cpu/armv7/exynos/power.c > @@ -37,6 +37,29 @@ void set_mipi_phy_ctrl(unsigned int dev_index, unsigned int enable) > exynos4_mipi_phy_control(dev_index, enable); > } > > +void exynos5_set_sata_phy_ctrl(unsigned int enable) > +{ > + struct exynos5_power *power = > + (struct exynos5_power *)samsung_get_base_power(); > + > + if (enable) { > + /* Enabling SATA_PHY */ > + setbits_le32(&power->sata_phy_control, > + POWER_USB_HOST_PHY_CTRL_EN); > + } else { > + /* Disabling SATA_PHY */ > + clrbits_le32(&power->sata_phy_control, > + POWER_USB_HOST_PHY_CTRL_EN); > + } > +} > + > +void set_sata_phy_ctrl(unsigned int enable) > +{ > + if (cpu_is_exynos5()) > + exynos5_set_sata_phy_ctrl(enable); > +} > + > + > void exynos5_set_usbhost_phy_ctrl(unsigned int enable) > { > struct exynos5_power *power = > diff --git a/arch/arm/cpu/armv7/exynos/sata.c b/arch/arm/cpu/armv7/exynos/sata.c > new file mode 100644 > index 0000000..4e994d6 > --- /dev/null > +++ b/arch/arm/cpu/armv7/exynos/sata.c > @@ -0,0 +1,412 @@ > +/* > + * Copyright (c) 2012 The Chromium OS Authors. > + * Copyright (c) 2014 Ian Campbell > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#include <asm/types.h> > +#include <ahci.h> > +#include <common.h> > +#include <fdtdec.h> > +#include <scsi.h> > +#include <asm/arch/sata.h> > +#include <asm/arch/pinmux.h> > +#include <asm/arch/clock.h> > +#include <asm/arch/clk.h> > +#include <asm/arch/power.h> > +#include <asm/errno.h> > +#include <asm/gpio.h> > +#include <linux/compiler.h> > + > +#define SATA_TIME_LIMIT 10000 > +#define SATA_PHY_I2C_SLAVE_ADDRS 0x70 > + > +/********************** PHY **************/ > + > +struct sata_phy { > + unsigned int res1; /* 0x00 */ > + unsigned int reset; /* 0x04 */ > +#define RESET_GLOBAL_RST_N (1 << 0) > +#define RESET_CMN_RST_N (1 << 1) > +#define RESET_CMN_BLOCK_RST_N (1 << 2) > +#define RESET_CMN_I2C_RST_N (1 << 3) > +#define RESET_TX_RX_PIPE_RST_N (1 << 4) > +#define RESET_TX_RX_BLOCK_RST_N (1 << 5) > +#define RESET_TX_RX_I2C_RST_N ((1 << 6) | (1 << 7)) > +#define LINK_RESET 0xF0000 > + unsigned int res2; /* 0x08 */ > + unsigned int res3; /* 0x0c */ > + unsigned int mode0; /* 0x10 */ > + unsigned int ctrl0; /* 0x14 */ > +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9) > +#define CTRL0_P0_PHY_CALIBRATED (1 << 8) > + unsigned int res4[0x32]; /* 0x18..0xdc */ > + unsigned int ctrlm; /* 0xE0 */ > +#define PHCTRLM_REF_RATE (1 << 1) > +#define PHCTRLM_HIGH_SPEED (1 << 0) > + unsigned int res5[0x03]; /* 0xE4..0xEF*/ > + unsigned int statm; /* 0xF0 */ > +#define PHSTATM_PLL_LOCKED (1 << 0) > +}; > + > +/********************** I2C **************/ > + > +struct sata_i2c { > + unsigned int con; /* 0x00 */ > + unsigned int stat; /* 0x04 */ > + unsigned int addr; /* 0x08 */ > + unsigned int ds; /* 0x0c */ > + unsigned int lc; /* 0x10 */ > +}; Can this be structured as an I2C device using driver model? It doesn't make sense to add new I2C drivers outside driver model. > + > +/* I2CCON reg */ > +#define CON_ACKEN (1 << 7) > +#define CON_CLK512 (1 << 6) > +#define CON_CLK16 (~CON_CLK512) > +#define CON_INTEN (1 << 5) > +#define CON_INTPND (1 << 4) > +#define CON_TXCLK_PS (0xF) > + > +/* I2CSTAT reg */ > +#define STAT_MSTT (0x3 << 6) > +#define STAT_BSYST (1 << 5) > +#define STAT_RTEN (1 << 4) > +#define STAT_LAST (1 << 0) > + > +#define LC_FLTR_EN (1 << 2) > + > +#define SATA_PHY_CON_RESET 0xF003F > + > +#define SATA_GENERATION1 (0) > +#define SATA_GENERATION2 (1 << 0) > +#define SATA_GENERATION3 (1 << 1) > + > +static bool sata_is_reg(void __iomem *reg, u32 checkbit, u32 status) > +{ > + if ((__raw_readl(reg) & checkbit) == status) > + return true; > + else > + return false; > +} > + > +static bool wait_for_reg_status(void __iomem *reg, u32 checkbit, u32 status) > +{ > + u32 time_limit_cnt = 0; > + > + while (!sata_is_reg(reg, checkbit, status)) { > + if (time_limit_cnt == SATA_TIME_LIMIT) > + return false; > + udelay(1000); > + time_limit_cnt++; > + } > + return true; > +} > + > +static void sata_set_gen(u8 gen) > +{ > + struct sata_phy *phy = > + (struct sata_phy *)samsung_get_base_sata_phy(); Should pass the base address into these functions. Also it can come from the device tree now. > + > + clrsetbits_le32(&phy->mode0, 0x3, gen); > +} > + > +/* Address :I2C Address */ > +static void sata_i2c_write_addrs(u8 data) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + __raw_writeb((data & 0xFE), &i2c->ds); > +} > + > +static void sata_i2c_write_data(u8 data) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + __raw_writeb((data), &i2c->ds); > +} > + > +static void sata_i2c_start(void) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + setbits_le32(&i2c->stat, STAT_BSYST); > +} > + > +static void sata_i2c_stop(void) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + clrbits_le32(&i2c->stat, STAT_BSYST); > +} > + > +static bool sata_i2c_get_int_status(void) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + if ((__raw_readl(&i2c->con)) & CON_INTPND) > + return true; > + else > + return false; > +} > + > +static bool sata_i2c_is_tx_ack(void) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + if ((__raw_readl(&i2c->con)) & STAT_LAST) > + return false; > + else > + return true; > +} > + > +static bool sata_i2c_is_bus_ready(void) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + if ((__raw_readl(&i2c->stat)) & STAT_BSYST) > + return false; > + else > + return true; > +} > + > +static bool sata_i2c_wait_for_busready(u32 time_out) > +{ > + while (--time_out) { > + if (sata_i2c_is_bus_ready()) > + return true; > + udelay(100); > + } > + return false; > +} > + > +static bool sata_i2c_wait_for_tx_ack(u32 time_out) > +{ > + while (--time_out) { > + if (sata_i2c_get_int_status()) { > + if (sata_i2c_is_tx_ack()) > + return true; > + } > + udelay(100); > + } > + return false; > +} > + > +static void sata_i2c_clear_int_status(void) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + clrbits_le32(&i2c->con, CON_INTPND); > +} > + > +static void sata_i2c_set_ack_gen(bool enable) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + if (enable) > + setbits_le32(&i2c->con, CON_ACKEN); > + else > + clrbits_le32(&i2c->con, CON_ACKEN); > +} > + > +static void sata_i2c_set_master_tx(void) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + /* Disable I2C */ > + clrbits_le32(&i2c->stat, STAT_RTEN); > + > + /* Clear Mode */ > + clrbits_le32(&i2c->stat, STAT_MSTT); > + > + sata_i2c_clear_int_status(); > + > + /* interrupt disable */ > + clrbits_le32(&i2c->con, CON_INTEN); > + > + /* Master, Send mode */ > + setbits_le32(&i2c->stat, STAT_MSTT); > + > + /* interrupt enable */ > + setbits_le32(&i2c->con, CON_INTEN); > + > + /* Enable I2C */ > + setbits_le32(&i2c->stat, STAT_RTEN); > +} > + > +static void sata_i2c_init(void) > +{ > + struct sata_i2c *i2c = > + (struct sata_i2c *)samsung_get_base_sata_i2c(); > + > + clrbits_le32(&i2c->con, ~CON_CLK16); > + clrbits_le32(&i2c->con, CON_TXCLK_PS); > + setbits_le32(&i2c->con, 2 & CON_TXCLK_PS); > + clrbits_le32(&i2c->lc, LC_FLTR_EN); > + > + sata_i2c_set_ack_gen(false); > +} > + > +static bool sata_i2c_send(u8 slave_addrs, u8 addrs, u8 data) Probably better to return an error code here rather than try/false. See errno.h. > +{ > + struct sata_phy *phy = > + (struct sata_phy *)samsung_get_base_sata_phy(); > + bool ret = false; > + > + if (!sata_i2c_wait_for_busready(SATA_TIME_LIMIT)) > + return false; > + > + sata_i2c_init(); > + sata_i2c_set_master_tx(); > + > + __raw_writel(SATA_PHY_CON_RESET, &phy->reset); > + sata_i2c_write_addrs(slave_addrs); > + sata_i2c_start(); > + > + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) > + goto stop; > + > + sata_i2c_write_data(addrs); > + sata_i2c_clear_int_status(); > + > + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) > + goto stop; > + > + sata_i2c_write_data(data); > + sata_i2c_clear_int_status(); > + > + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) > + goto stop; > + > + ret = true; > + > +stop: > + sata_i2c_stop(); > + sata_i2c_clear_int_status(); > + sata_i2c_wait_for_busready(SATA_TIME_LIMIT); Error check here? > + > + return ret; > +} > + > +static bool ahci_phy_init(void) > +{ > + return sata_i2c_send(SATA_PHY_I2C_SLAVE_ADDRS, 0x3a, 0x0b); > +} > + > +static int exynos5_ahci_init(void) > +{ > + struct sata_phy *phy = > + (struct sata_phy *)samsung_get_base_sata_phy(); > + int ret; > + > + if (sata_is_reg(&phy->ctrl0, > + CTRL0_P0_PHY_CALIBRATED, CTRL0_P0_PHY_CALIBRATED)) { > + printf("%s: already calibrated?\n", __func__); > + } > + > + /* Clear phy control enable. Seems to be necessary to > + * reinitialise on a warm reboot, at least sometimes. */ > + set_sata_phy_ctrl(0); > + udelay(1000); > + > + set_sata_phy_ctrl(1); > + > + __raw_writel(0, &phy->reset); > + setbits_le32(&phy->reset, > + RESET_GLOBAL_RST_N| > + RESET_CMN_BLOCK_RST_N|RESET_CMN_I2C_RST_N| > + RESET_TX_RX_PIPE_RST_N|RESET_TX_RX_BLOCK_RST_N); > + > + setbits_le32(&phy->reset, LINK_RESET); > + > + setbits_le32(&phy->reset, RESET_CMN_RST_N); > + > + clrbits_le32(&phy->ctrlm, PHCTRLM_REF_RATE); > + > + /* High speed enable for Gen3 */ > + setbits_le32(&phy->ctrlm, PHCTRLM_HIGH_SPEED); > + > + setbits_le32(&phy->ctrl0, > + CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED); > + > + sata_set_gen(SATA_GENERATION3); > + > + ret = ahci_phy_init(); Return if there is an error? > + > + /* release cmu reset */ > + clrbits_le32(&phy->reset, RESET_CMN_RST_N); > + > + setbits_le32(&phy->reset, RESET_CMN_RST_N); > + > + if (wait_for_reg_status(&phy->statm, > + PHSTATM_PLL_LOCKED, 1)) > + return ret; > + > + return 0; > +} > + > +static void exynos5_enable_clock_gates(void) > +{ > + struct exynos5_clock *clk = > + (struct exynos5_clock *)samsung_get_base_clock(); > + > + /* Turn on all SATA clock gates & DMA gates. */ > + const unsigned sata_clocks = (1 << 25) | (1 << 24) | (1 << 6); > + const unsigned dma_clocks = (2 << 1) | (1 << 1); > + > + setbits_le32(&clk->gate_ip_fsys, sata_clocks|dma_clocks); > +} > + > +int exynos5_sata_init(void) > +{ > + BUILD_BUG_ON(offsetof(struct sata_phy, reset) != 0x04); > + BUILD_BUG_ON(offsetof(struct sata_phy, mode0) != 0x10); > + BUILD_BUG_ON(offsetof(struct sata_phy, ctrl0) != 0x14); > + BUILD_BUG_ON(offsetof(struct sata_phy, ctrlm) != 0xe0); > + BUILD_BUG_ON(offsetof(struct sata_phy, statm) != 0xf0); > + > + BUILD_BUG_ON(offsetof(struct sata_i2c, con) != 0x00); > + BUILD_BUG_ON(offsetof(struct sata_i2c, stat) != 0x04); > + BUILD_BUG_ON(offsetof(struct sata_i2c, addr) != 0x08); > + BUILD_BUG_ON(offsetof(struct sata_i2c, ds) != 0x0c); > + BUILD_BUG_ON(offsetof(struct sata_i2c, lc) != 0x10); > + > + exynos5_enable_clock_gates(); > + > + if (exynos5_ahci_init()) { Non-zero return from this function should mean error. > + ahci_init(samsung_get_base_sata_axi()); > + return 0; > + } > + return -ENODEV; > +} > + > +int exynos5_sata_deinit(void) > +{ > + struct sata_phy *phy = > + (struct sata_phy *)samsung_get_base_sata_phy(); > + > + sata_set_gen(SATA_GENERATION1); > + > + clrbits_le32(&phy->ctrl0, > + CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED); > + > + /* Disable High speed enable for Gen3 */ > + clrbits_le32(&phy->ctrlm, PHCTRLM_HIGH_SPEED); > + > + setbits_le32(&phy->ctrlm, PHCTRLM_REF_RATE); > + > + __raw_writel(0, &phy->reset); > + > + set_sata_phy_ctrl(0); > + > + return 0; > +} > diff --git a/arch/arm/cpu/armv7/exynos/soc.c b/arch/arm/cpu/armv7/exynos/soc.c > index 8c7d7d8..1cd8b7b 100644 > --- a/arch/arm/cpu/armv7/exynos/soc.c > +++ b/arch/arm/cpu/armv7/exynos/soc.c > @@ -8,6 +8,7 @@ > #include <common.h> > #include <asm/io.h> > #include <asm/system.h> > +#include <asm/arch/sata.h> > > enum l2_cache_params { > CACHE_TAG_RAM_SETUP = (1 << 9), > @@ -29,6 +30,13 @@ void enable_caches(void) > } > #endif > > +void arch_preboot_os(void) > +{ > +#if defined(CONFIG_SCSI_AHCI) > + exynos5_sata_deinit(); > +#endif > +} > + > #ifndef CONFIG_SYS_L2CACHE_OFF > /* > * Set L2 cache parameters > diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h > index 29674ad..7d53995 100644 > --- a/arch/arm/include/asm/arch-exynos/cpu.h > +++ b/arch/arm/include/asm/arch-exynos/cpu.h > @@ -56,6 +56,9 @@ > #define EXYNOS4_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE > #define EXYNOS4_USB3PHY_BASE DEVICE_NOT_AVAILABLE > #define EXYNOS4_DMC_TZASC_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS4_SATA_PHY_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS4_SATA_I2C_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS4_SATA_AXI_BASE DEVICE_NOT_AVAILABLE Please we don't need these constants anymore. > > /* EXYNOS4X12 */ > #define EXYNOS4X12_GPIO_PART3_BASE 0x03860000 > @@ -102,6 +105,9 @@ > #define EXYNOS4X12_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE > #define EXYNOS4X12_USB3PHY_BASE DEVICE_NOT_AVAILABLE > #define EXYNOS4X12_DMC_TZASC_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS4X12_SATA_PHY_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS4X12_SATA_I2C_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS4X12_SATA_AXI_BASE DEVICE_NOT_AVAILABLE > > /* EXYNOS5 */ > #define EXYNOS5_I2C_SPACING 0x10000 > @@ -130,8 +136,11 @@ > #define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000 > #define EXYNOS5_USBPHY_BASE 0x12130000 > #define EXYNOS5_USBOTG_BASE 0x12140000 > +#define EXYNOS5_SATA_PHY_BASE 0x12170000 > +#define EXYNOS5_SATA_I2C_BASE 0x121d0000 > #define EXYNOS5_MMC_BASE 0x12200000 > #define EXYNOS5_SROMC_BASE 0x12250000 > +#define EXYNOS5_SATA_AXI_BASE 0x122f0000 > #define EXYNOS5_UART_BASE 0x12C00000 > #define EXYNOS5_I2C_BASE 0x12C60000 > #define EXYNOS5_SPI_BASE 0x12D20000 > @@ -185,6 +194,9 @@ > #define EXYNOS5420_MODEM_BASE DEVICE_NOT_AVAILABLE > #define EXYNOS5420_USB3PHY_BASE DEVICE_NOT_AVAILABLE > #define EXYNOS5420_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS5420_SATA_PHY_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS5420_SATA_I2C_BASE DEVICE_NOT_AVAILABLE > +#define EXYNOS5420_SATA_AXI_BASE DEVICE_NOT_AVAILABLE > > #ifndef __ASSEMBLY__ > #include <asm/io.h> > @@ -314,6 +326,9 @@ SAMSUNG_BASE(dmc_ctrl, DMC_CTRL_BASE) > SAMSUNG_BASE(dmc_phy, DMC_PHY_BASE) > SAMSUNG_BASE(dmc_tzasc, DMC_TZASC_BASE) > SAMSUNG_BASE(audio_ass, AUDIOSS_BASE) > +SAMSUNG_BASE(sata_phy, SATA_PHY_BASE) > +SAMSUNG_BASE(sata_i2c, SATA_I2C_BASE) > +SAMSUNG_BASE(sata_axi, SATA_AXI_BASE) > #endif > > #endif /* _EXYNOS4_CPU_H */ > diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h > index 3f97b31..da023ea 100644 > --- a/arch/arm/include/asm/arch-exynos/power.h > +++ b/arch/arm/include/asm/arch-exynos/power.h > @@ -1704,6 +1704,10 @@ void set_mipi_phy_ctrl(unsigned int dev_index, unsigned int enable); > #define EXYNOS_MIPI_PHY_SRESETN (1 << 1) > #define EXYNOS_MIPI_PHY_MRESETN (1 << 2) > > +void set_sata_phy_ctrl(unsigned int enable); Function docs? > + > +#define EXYNOS_SATA_PHY_CONTROL_EN (1 << 0) > + > void set_usbhost_phy_ctrl(unsigned int enable); > > /* Enables hardware tripping to power off the system when TMU fails */ > diff --git a/arch/arm/include/asm/arch-exynos/sata.h b/arch/arm/include/asm/arch-exynos/sata.h > new file mode 100644 > index 0000000..94c7736 > --- /dev/null > +++ b/arch/arm/include/asm/arch-exynos/sata.h > @@ -0,0 +1,13 @@ > +/* > + * Copyright (c) 2012 The Chromium OS Authors. > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#ifndef __EXYNOS5_SATA_H > +#define __EXYNOS5_SATA_H > + > +int exynos5_sata_init(void); > +int exynos5_sata_deinit(void); > + > +#endif > + > diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c > index f606255..0de0c76 100644 > --- a/arch/arm/lib/board.c > +++ b/arch/arm/lib/board.c > @@ -35,6 +35,7 @@ > #include <mmc.h> > #include <scsi.h> > #include <status_led.h> > +#include <sata.h> > #include <libfdt.h> > #include <fdtdec.h> > #include <post.h> > diff --git a/board/samsung/arndale/arndale.c b/board/samsung/arndale/arndale.c > index 881d080..43f4058 100644 > --- a/board/samsung/arndale/arndale.c > +++ b/board/samsung/arndale/arndale.c > @@ -10,6 +10,7 @@ > #include <asm/arch/pinmux.h> > #include <asm/arch/dwmmc.h> > #include <asm/arch/power.h> > +#include <asm/arch/sata.h> > > DECLARE_GLOBAL_DATA_PTR; > > @@ -31,6 +32,14 @@ int board_usb_init(int index, enum usb_init_type init) > } > #endif > > +#ifdef CONFIG_SCSI_AHCI > +int scsi_init(void) > +{ > + printf("ARNDALE SCSI INIT\n"); > + return exynos5_sata_init(); This could go in standard Samsung board.c, there does not seem to be anything arndale-specific. > +} > +#endif > + > int board_init(void) > { > gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); > diff --git a/include/configs/arndale.h b/include/configs/arndale.h > index 81e8a7c..85e9295 100644 > --- a/include/configs/arndale.h > +++ b/include/configs/arndale.h > @@ -12,6 +12,9 @@ > #define EXYNOS_FDTFILE_SETTING \ > "fdtfile=exynos5250-arndale.dtb\0" > > +/* AHCI */ > +#define CONFIG_EXYNOS5250_AHCI > + > #include "exynos5250-common.h" > > /* SD/MMC configuration */ > diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h > index e1f5783..3000c97 100644 > --- a/include/configs/exynos5-common.h > +++ b/include/configs/exynos5-common.h > @@ -163,6 +163,18 @@ > #define CONFIG_ENV_SROM_BANK 1 > #endif /*CONFIG_CMD_NET*/ > > +/* SATA controller driver */ > +#ifdef CONFIG_EXYNOS5250_AHCI > +#define CONFIG_CMD_SCSI > +#define CONFIG_SYS_SCSI_MAX_SCSI_ID 1 > +#define CONFIG_SYS_SCSI_MAX_LUN 1 > +#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ > + CONFIG_SYS_SCSI_MAX_LUN) > +#define CONFIG_LIBATA > +#define CONFIG_SCSI_AHCI > +#define CONFIG_SCSI_AHCI_PLAT > +#endif > + > /* SHA hashing */ > #define CONFIG_CMD_HASH > #define CONFIG_HASH_VERIFY > @@ -184,10 +196,16 @@ > #define CONFIG_FIT > #define CONFIG_FIT_BEST_MATCH > > +#ifdef CONFIG_EXYNOS5250_AHCI > +#define BOOT_TARGET_DEVICES_SCSI(func) func(SCSI, scsi, 0) > +#else > +#define BOOT_TARGET_DEVICES_SCSI(func) > +#endif > > #define BOOT_TARGET_DEVICES(func) \ > func(MMC, mmc, 1) \ > func(MMC, mmc, 0) \ > + BOOT_TARGET_DEVICES_SCSI(func) \ Great! > func(PXE, pxe, na) \ > func(DHCP, dhcp, na) > > -- > 2.1.1 > Regards, Simon
diff --git a/arch/arm/cpu/armv7/exynos/Makefile b/arch/arm/cpu/armv7/exynos/Makefile index e207bd6..c74a2d4 100644 --- a/arch/arm/cpu/armv7/exynos/Makefile +++ b/arch/arm/cpu/armv7/exynos/Makefile @@ -7,6 +7,10 @@ obj-y += clock.o power.o soc.o system.o pinmux.o tzpc.o +ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_EXYNOS5250_AHCI) += sata.o +endif + ifdef CONFIG_SPL_BUILD obj-$(CONFIG_EXYNOS5) += clock_init_exynos5.o obj-$(CONFIG_EXYNOS5) += dmc_common.o dmc_init_ddr3.o diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c index 1520d64..8f36d10 100644 --- a/arch/arm/cpu/armv7/exynos/power.c +++ b/arch/arm/cpu/armv7/exynos/power.c @@ -37,6 +37,29 @@ void set_mipi_phy_ctrl(unsigned int dev_index, unsigned int enable) exynos4_mipi_phy_control(dev_index, enable); } +void exynos5_set_sata_phy_ctrl(unsigned int enable) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + if (enable) { + /* Enabling SATA_PHY */ + setbits_le32(&power->sata_phy_control, + POWER_USB_HOST_PHY_CTRL_EN); + } else { + /* Disabling SATA_PHY */ + clrbits_le32(&power->sata_phy_control, + POWER_USB_HOST_PHY_CTRL_EN); + } +} + +void set_sata_phy_ctrl(unsigned int enable) +{ + if (cpu_is_exynos5()) + exynos5_set_sata_phy_ctrl(enable); +} + + void exynos5_set_usbhost_phy_ctrl(unsigned int enable) { struct exynos5_power *power = diff --git a/arch/arm/cpu/armv7/exynos/sata.c b/arch/arm/cpu/armv7/exynos/sata.c new file mode 100644 index 0000000..4e994d6 --- /dev/null +++ b/arch/arm/cpu/armv7/exynos/sata.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * Copyright (c) 2014 Ian Campbell + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <asm/types.h> +#include <ahci.h> +#include <common.h> +#include <fdtdec.h> +#include <scsi.h> +#include <asm/arch/sata.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/clock.h> +#include <asm/arch/clk.h> +#include <asm/arch/power.h> +#include <asm/errno.h> +#include <asm/gpio.h> +#include <linux/compiler.h> + +#define SATA_TIME_LIMIT 10000 +#define SATA_PHY_I2C_SLAVE_ADDRS 0x70 + +/********************** PHY **************/ + +struct sata_phy { + unsigned int res1; /* 0x00 */ + unsigned int reset; /* 0x04 */ +#define RESET_GLOBAL_RST_N (1 << 0) +#define RESET_CMN_RST_N (1 << 1) +#define RESET_CMN_BLOCK_RST_N (1 << 2) +#define RESET_CMN_I2C_RST_N (1 << 3) +#define RESET_TX_RX_PIPE_RST_N (1 << 4) +#define RESET_TX_RX_BLOCK_RST_N (1 << 5) +#define RESET_TX_RX_I2C_RST_N ((1 << 6) | (1 << 7)) +#define LINK_RESET 0xF0000 + unsigned int res2; /* 0x08 */ + unsigned int res3; /* 0x0c */ + unsigned int mode0; /* 0x10 */ + unsigned int ctrl0; /* 0x14 */ +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9) +#define CTRL0_P0_PHY_CALIBRATED (1 << 8) + unsigned int res4[0x32]; /* 0x18..0xdc */ + unsigned int ctrlm; /* 0xE0 */ +#define PHCTRLM_REF_RATE (1 << 1) +#define PHCTRLM_HIGH_SPEED (1 << 0) + unsigned int res5[0x03]; /* 0xE4..0xEF*/ + unsigned int statm; /* 0xF0 */ +#define PHSTATM_PLL_LOCKED (1 << 0) +}; + +/********************** I2C **************/ + +struct sata_i2c { + unsigned int con; /* 0x00 */ + unsigned int stat; /* 0x04 */ + unsigned int addr; /* 0x08 */ + unsigned int ds; /* 0x0c */ + unsigned int lc; /* 0x10 */ +}; + +/* I2CCON reg */ +#define CON_ACKEN (1 << 7) +#define CON_CLK512 (1 << 6) +#define CON_CLK16 (~CON_CLK512) +#define CON_INTEN (1 << 5) +#define CON_INTPND (1 << 4) +#define CON_TXCLK_PS (0xF) + +/* I2CSTAT reg */ +#define STAT_MSTT (0x3 << 6) +#define STAT_BSYST (1 << 5) +#define STAT_RTEN (1 << 4) +#define STAT_LAST (1 << 0) + +#define LC_FLTR_EN (1 << 2) + +#define SATA_PHY_CON_RESET 0xF003F + +#define SATA_GENERATION1 (0) +#define SATA_GENERATION2 (1 << 0) +#define SATA_GENERATION3 (1 << 1) + +static bool sata_is_reg(void __iomem *reg, u32 checkbit, u32 status) +{ + if ((__raw_readl(reg) & checkbit) == status) + return true; + else + return false; +} + +static bool wait_for_reg_status(void __iomem *reg, u32 checkbit, u32 status) +{ + u32 time_limit_cnt = 0; + + while (!sata_is_reg(reg, checkbit, status)) { + if (time_limit_cnt == SATA_TIME_LIMIT) + return false; + udelay(1000); + time_limit_cnt++; + } + return true; +} + +static void sata_set_gen(u8 gen) +{ + struct sata_phy *phy = + (struct sata_phy *)samsung_get_base_sata_phy(); + + clrsetbits_le32(&phy->mode0, 0x3, gen); +} + +/* Address :I2C Address */ +static void sata_i2c_write_addrs(u8 data) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + __raw_writeb((data & 0xFE), &i2c->ds); +} + +static void sata_i2c_write_data(u8 data) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + __raw_writeb((data), &i2c->ds); +} + +static void sata_i2c_start(void) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + setbits_le32(&i2c->stat, STAT_BSYST); +} + +static void sata_i2c_stop(void) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + clrbits_le32(&i2c->stat, STAT_BSYST); +} + +static bool sata_i2c_get_int_status(void) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + if ((__raw_readl(&i2c->con)) & CON_INTPND) + return true; + else + return false; +} + +static bool sata_i2c_is_tx_ack(void) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + if ((__raw_readl(&i2c->con)) & STAT_LAST) + return false; + else + return true; +} + +static bool sata_i2c_is_bus_ready(void) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + if ((__raw_readl(&i2c->stat)) & STAT_BSYST) + return false; + else + return true; +} + +static bool sata_i2c_wait_for_busready(u32 time_out) +{ + while (--time_out) { + if (sata_i2c_is_bus_ready()) + return true; + udelay(100); + } + return false; +} + +static bool sata_i2c_wait_for_tx_ack(u32 time_out) +{ + while (--time_out) { + if (sata_i2c_get_int_status()) { + if (sata_i2c_is_tx_ack()) + return true; + } + udelay(100); + } + return false; +} + +static void sata_i2c_clear_int_status(void) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + clrbits_le32(&i2c->con, CON_INTPND); +} + +static void sata_i2c_set_ack_gen(bool enable) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + if (enable) + setbits_le32(&i2c->con, CON_ACKEN); + else + clrbits_le32(&i2c->con, CON_ACKEN); +} + +static void sata_i2c_set_master_tx(void) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + /* Disable I2C */ + clrbits_le32(&i2c->stat, STAT_RTEN); + + /* Clear Mode */ + clrbits_le32(&i2c->stat, STAT_MSTT); + + sata_i2c_clear_int_status(); + + /* interrupt disable */ + clrbits_le32(&i2c->con, CON_INTEN); + + /* Master, Send mode */ + setbits_le32(&i2c->stat, STAT_MSTT); + + /* interrupt enable */ + setbits_le32(&i2c->con, CON_INTEN); + + /* Enable I2C */ + setbits_le32(&i2c->stat, STAT_RTEN); +} + +static void sata_i2c_init(void) +{ + struct sata_i2c *i2c = + (struct sata_i2c *)samsung_get_base_sata_i2c(); + + clrbits_le32(&i2c->con, ~CON_CLK16); + clrbits_le32(&i2c->con, CON_TXCLK_PS); + setbits_le32(&i2c->con, 2 & CON_TXCLK_PS); + clrbits_le32(&i2c->lc, LC_FLTR_EN); + + sata_i2c_set_ack_gen(false); +} + +static bool sata_i2c_send(u8 slave_addrs, u8 addrs, u8 data) +{ + struct sata_phy *phy = + (struct sata_phy *)samsung_get_base_sata_phy(); + bool ret = false; + + if (!sata_i2c_wait_for_busready(SATA_TIME_LIMIT)) + return false; + + sata_i2c_init(); + sata_i2c_set_master_tx(); + + __raw_writel(SATA_PHY_CON_RESET, &phy->reset); + sata_i2c_write_addrs(slave_addrs); + sata_i2c_start(); + + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) + goto stop; + + sata_i2c_write_data(addrs); + sata_i2c_clear_int_status(); + + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) + goto stop; + + sata_i2c_write_data(data); + sata_i2c_clear_int_status(); + + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) + goto stop; + + ret = true; + +stop: + sata_i2c_stop(); + sata_i2c_clear_int_status(); + sata_i2c_wait_for_busready(SATA_TIME_LIMIT); + + return ret; +} + +static bool ahci_phy_init(void) +{ + return sata_i2c_send(SATA_PHY_I2C_SLAVE_ADDRS, 0x3a, 0x0b); +} + +static int exynos5_ahci_init(void) +{ + struct sata_phy *phy = + (struct sata_phy *)samsung_get_base_sata_phy(); + int ret; + + if (sata_is_reg(&phy->ctrl0, + CTRL0_P0_PHY_CALIBRATED, CTRL0_P0_PHY_CALIBRATED)) { + printf("%s: already calibrated?\n", __func__); + } + + /* Clear phy control enable. Seems to be necessary to + * reinitialise on a warm reboot, at least sometimes. */ + set_sata_phy_ctrl(0); + udelay(1000); + + set_sata_phy_ctrl(1); + + __raw_writel(0, &phy->reset); + setbits_le32(&phy->reset, + RESET_GLOBAL_RST_N| + RESET_CMN_BLOCK_RST_N|RESET_CMN_I2C_RST_N| + RESET_TX_RX_PIPE_RST_N|RESET_TX_RX_BLOCK_RST_N); + + setbits_le32(&phy->reset, LINK_RESET); + + setbits_le32(&phy->reset, RESET_CMN_RST_N); + + clrbits_le32(&phy->ctrlm, PHCTRLM_REF_RATE); + + /* High speed enable for Gen3 */ + setbits_le32(&phy->ctrlm, PHCTRLM_HIGH_SPEED); + + setbits_le32(&phy->ctrl0, + CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED); + + sata_set_gen(SATA_GENERATION3); + + ret = ahci_phy_init(); + + /* release cmu reset */ + clrbits_le32(&phy->reset, RESET_CMN_RST_N); + + setbits_le32(&phy->reset, RESET_CMN_RST_N); + + if (wait_for_reg_status(&phy->statm, + PHSTATM_PLL_LOCKED, 1)) + return ret; + + return 0; +} + +static void exynos5_enable_clock_gates(void) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + /* Turn on all SATA clock gates & DMA gates. */ + const unsigned sata_clocks = (1 << 25) | (1 << 24) | (1 << 6); + const unsigned dma_clocks = (2 << 1) | (1 << 1); + + setbits_le32(&clk->gate_ip_fsys, sata_clocks|dma_clocks); +} + +int exynos5_sata_init(void) +{ + BUILD_BUG_ON(offsetof(struct sata_phy, reset) != 0x04); + BUILD_BUG_ON(offsetof(struct sata_phy, mode0) != 0x10); + BUILD_BUG_ON(offsetof(struct sata_phy, ctrl0) != 0x14); + BUILD_BUG_ON(offsetof(struct sata_phy, ctrlm) != 0xe0); + BUILD_BUG_ON(offsetof(struct sata_phy, statm) != 0xf0); + + BUILD_BUG_ON(offsetof(struct sata_i2c, con) != 0x00); + BUILD_BUG_ON(offsetof(struct sata_i2c, stat) != 0x04); + BUILD_BUG_ON(offsetof(struct sata_i2c, addr) != 0x08); + BUILD_BUG_ON(offsetof(struct sata_i2c, ds) != 0x0c); + BUILD_BUG_ON(offsetof(struct sata_i2c, lc) != 0x10); + + exynos5_enable_clock_gates(); + + if (exynos5_ahci_init()) { + ahci_init(samsung_get_base_sata_axi()); + return 0; + } + return -ENODEV; +} + +int exynos5_sata_deinit(void) +{ + struct sata_phy *phy = + (struct sata_phy *)samsung_get_base_sata_phy(); + + sata_set_gen(SATA_GENERATION1); + + clrbits_le32(&phy->ctrl0, + CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED); + + /* Disable High speed enable for Gen3 */ + clrbits_le32(&phy->ctrlm, PHCTRLM_HIGH_SPEED); + + setbits_le32(&phy->ctrlm, PHCTRLM_REF_RATE); + + __raw_writel(0, &phy->reset); + + set_sata_phy_ctrl(0); + + return 0; +} diff --git a/arch/arm/cpu/armv7/exynos/soc.c b/arch/arm/cpu/armv7/exynos/soc.c index 8c7d7d8..1cd8b7b 100644 --- a/arch/arm/cpu/armv7/exynos/soc.c +++ b/arch/arm/cpu/armv7/exynos/soc.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <asm/system.h> +#include <asm/arch/sata.h> enum l2_cache_params { CACHE_TAG_RAM_SETUP = (1 << 9), @@ -29,6 +30,13 @@ void enable_caches(void) } #endif +void arch_preboot_os(void) +{ +#if defined(CONFIG_SCSI_AHCI) + exynos5_sata_deinit(); +#endif +} + #ifndef CONFIG_SYS_L2CACHE_OFF /* * Set L2 cache parameters diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index 29674ad..7d53995 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -56,6 +56,9 @@ #define EXYNOS4_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_USB3PHY_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_DMC_TZASC_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4_SATA_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4_SATA_I2C_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4_SATA_AXI_BASE DEVICE_NOT_AVAILABLE /* EXYNOS4X12 */ #define EXYNOS4X12_GPIO_PART3_BASE 0x03860000 @@ -102,6 +105,9 @@ #define EXYNOS4X12_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4X12_USB3PHY_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4X12_DMC_TZASC_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4X12_SATA_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4X12_SATA_I2C_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4X12_SATA_AXI_BASE DEVICE_NOT_AVAILABLE /* EXYNOS5 */ #define EXYNOS5_I2C_SPACING 0x10000 @@ -130,8 +136,11 @@ #define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000 #define EXYNOS5_USBPHY_BASE 0x12130000 #define EXYNOS5_USBOTG_BASE 0x12140000 +#define EXYNOS5_SATA_PHY_BASE 0x12170000 +#define EXYNOS5_SATA_I2C_BASE 0x121d0000 #define EXYNOS5_MMC_BASE 0x12200000 #define EXYNOS5_SROMC_BASE 0x12250000 +#define EXYNOS5_SATA_AXI_BASE 0x122f0000 #define EXYNOS5_UART_BASE 0x12C00000 #define EXYNOS5_I2C_BASE 0x12C60000 #define EXYNOS5_SPI_BASE 0x12D20000 @@ -185,6 +194,9 @@ #define EXYNOS5420_MODEM_BASE DEVICE_NOT_AVAILABLE #define EXYNOS5420_USB3PHY_BASE DEVICE_NOT_AVAILABLE #define EXYNOS5420_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS5420_SATA_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS5420_SATA_I2C_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS5420_SATA_AXI_BASE DEVICE_NOT_AVAILABLE #ifndef __ASSEMBLY__ #include <asm/io.h> @@ -314,6 +326,9 @@ SAMSUNG_BASE(dmc_ctrl, DMC_CTRL_BASE) SAMSUNG_BASE(dmc_phy, DMC_PHY_BASE) SAMSUNG_BASE(dmc_tzasc, DMC_TZASC_BASE) SAMSUNG_BASE(audio_ass, AUDIOSS_BASE) +SAMSUNG_BASE(sata_phy, SATA_PHY_BASE) +SAMSUNG_BASE(sata_i2c, SATA_I2C_BASE) +SAMSUNG_BASE(sata_axi, SATA_AXI_BASE) #endif #endif /* _EXYNOS4_CPU_H */ diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h index 3f97b31..da023ea 100644 --- a/arch/arm/include/asm/arch-exynos/power.h +++ b/arch/arm/include/asm/arch-exynos/power.h @@ -1704,6 +1704,10 @@ void set_mipi_phy_ctrl(unsigned int dev_index, unsigned int enable); #define EXYNOS_MIPI_PHY_SRESETN (1 << 1) #define EXYNOS_MIPI_PHY_MRESETN (1 << 2) +void set_sata_phy_ctrl(unsigned int enable); + +#define EXYNOS_SATA_PHY_CONTROL_EN (1 << 0) + void set_usbhost_phy_ctrl(unsigned int enable); /* Enables hardware tripping to power off the system when TMU fails */ diff --git a/arch/arm/include/asm/arch-exynos/sata.h b/arch/arm/include/asm/arch-exynos/sata.h new file mode 100644 index 0000000..94c7736 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/sata.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef __EXYNOS5_SATA_H +#define __EXYNOS5_SATA_H + +int exynos5_sata_init(void); +int exynos5_sata_deinit(void); + +#endif + diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f606255..0de0c76 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -35,6 +35,7 @@ #include <mmc.h> #include <scsi.h> #include <status_led.h> +#include <sata.h> #include <libfdt.h> #include <fdtdec.h> #include <post.h> diff --git a/board/samsung/arndale/arndale.c b/board/samsung/arndale/arndale.c index 881d080..43f4058 100644 --- a/board/samsung/arndale/arndale.c +++ b/board/samsung/arndale/arndale.c @@ -10,6 +10,7 @@ #include <asm/arch/pinmux.h> #include <asm/arch/dwmmc.h> #include <asm/arch/power.h> +#include <asm/arch/sata.h> DECLARE_GLOBAL_DATA_PTR; @@ -31,6 +32,14 @@ int board_usb_init(int index, enum usb_init_type init) } #endif +#ifdef CONFIG_SCSI_AHCI +int scsi_init(void) +{ + printf("ARNDALE SCSI INIT\n"); + return exynos5_sata_init(); +} +#endif + int board_init(void) { gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); diff --git a/include/configs/arndale.h b/include/configs/arndale.h index 81e8a7c..85e9295 100644 --- a/include/configs/arndale.h +++ b/include/configs/arndale.h @@ -12,6 +12,9 @@ #define EXYNOS_FDTFILE_SETTING \ "fdtfile=exynos5250-arndale.dtb\0" +/* AHCI */ +#define CONFIG_EXYNOS5250_AHCI + #include "exynos5250-common.h" /* SD/MMC configuration */ diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h index e1f5783..3000c97 100644 --- a/include/configs/exynos5-common.h +++ b/include/configs/exynos5-common.h @@ -163,6 +163,18 @@ #define CONFIG_ENV_SROM_BANK 1 #endif /*CONFIG_CMD_NET*/ +/* SATA controller driver */ +#ifdef CONFIG_EXYNOS5250_AHCI +#define CONFIG_CMD_SCSI +#define CONFIG_SYS_SCSI_MAX_SCSI_ID 1 +#define CONFIG_SYS_SCSI_MAX_LUN 1 +#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ + CONFIG_SYS_SCSI_MAX_LUN) +#define CONFIG_LIBATA +#define CONFIG_SCSI_AHCI +#define CONFIG_SCSI_AHCI_PLAT +#endif + /* SHA hashing */ #define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -184,10 +196,16 @@ #define CONFIG_FIT #define CONFIG_FIT_BEST_MATCH +#ifdef CONFIG_EXYNOS5250_AHCI +#define BOOT_TARGET_DEVICES_SCSI(func) func(SCSI, scsi, 0) +#else +#define BOOT_TARGET_DEVICES_SCSI(func) +#endif #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 1) \ func(MMC, mmc, 0) \ + BOOT_TARGET_DEVICES_SCSI(func) \ func(PXE, pxe, na) \ func(DHCP, dhcp, na)