From: Ian Campbell <ian.campb...@citrix.com> 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 <th...@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 <th...@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 <th...@chromium.org> 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. This relies on "ahci: Don't start command DMA engine before buffers are set" NOTE: For some reason when running u-boot with this patch Linux is unable to correct probe devices. See the next patch for an attempt at a hack/workaround. Any ideas would be appreciated. Signed-off-by: Ian Campbell <ian.campb...@citrix.com> Cc: Taylor Hutt <th...@chromium.org> Cc: Simon Glass <s...@chromium.org> --- arch/arm/cpu/armv7/exynos/Makefile | 4 + arch/arm/cpu/armv7/exynos/sata.c | 370 ++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/sata.h | 29 +++ arch/arm/lib/board.c | 1 + board/samsung/arndale/arndale.c | 9 + include/configs/arndale.h | 13 ++ 6 files changed, 426 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/sata.c b/arch/arm/cpu/armv7/exynos/sata.c new file mode 100644 index 0000000..14d42e7 --- /dev/null +++ b/arch/arm/cpu/armv7/exynos/sata.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#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/errno.h> +#include <asm/gpio.h> +#include <linux/compiler.h> + +#define SATA_AHCI_AXI 0x122f0000 +#define SATA_PHCTRL_APB 0x12170000 +#define SATA_PHY_I2C_ABP 0x121d0000 +#define EXYNOS5_SATA_PHY_CONTROL (0x10040000 + 0x724) +#define S5P_PMU_SATA_PHY_CONTROL_EN 0x1 + +void * const phy_ctrl = (void *)SATA_PHCTRL_APB; +void * const phy_i2c_base = (void *)SATA_PHY_I2C_ABP; + +#define SATA_TIME_LIMIT 10000 +#define SATA_PHY_I2C_SLAVE_ADDRS 0x70 + +#define SATA_RESET 0x4 +#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) | BIT(7)) + +#define LINK_RESET 0xF0000 + +#define SATA_MODE0 0x10 + +#define SATA_CTRL0 0x14 +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9) +#define CTRL0_P0_PHY_CALIBRATED (1 << 8) + +#define SATA_PHSATA_CTRLM 0xE0 +#define PHCTRLM_REF_RATE (1 << 1) +#define PHCTRLM_HIGH_SPEED (1 << 0) + +#define SATA_PHSATA_STATM 0xF0 +#define PHSTATM_PLL_LOCKED (1 << 0) + + +/********************** I2C**************/ +#define SATA_I2C_CON 0x00 +#define SATA_I2C_STAT 0x04 +#define SATA_I2C_ADDR 0x08 +#define SATA_I2C_DS 0x0C +#define SATA_I2C_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 SCLK_SATA_FREQ (66 * MHZ) + + + +enum { + SATA_GENERATION1, + SATA_GENERATION2, + SATA_GENERATION3, +}; + +static bool sata_is_reg(void __iomem *base, u32 reg, u32 checkbit, u32 Status) +{ + if ((__raw_readl(base + reg) & checkbit) == Status) + return true; + else + return false; +} + +static bool wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit, + u32 Status) +{ + u32 time_limit_cnt = 0; + while (!sata_is_reg(base, 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) +{ + setbits_le32(phy_ctrl + SATA_MODE0, gen); +} + +/* Address :I2C Address */ +static void sata_i2c_write_addrs(u8 data) +{ + __raw_writeb((data & 0xFE), phy_i2c_base + SATA_I2C_DS); +} + +static void sata_i2c_write_data(u8 data) +{ + __raw_writeb((data), phy_i2c_base + SATA_I2C_DS); +} + +static void sata_i2c_start(void) +{ + setbits_le32(phy_i2c_base + SATA_I2C_STAT, STAT_BSYST); +} + +static void sata_i2c_stop(void) +{ + clrbits_le32(phy_i2c_base + SATA_I2C_STAT, STAT_BSYST); +} + +static bool sata_i2c_get_int_status(void) +{ + if ((__raw_readl(phy_i2c_base + SATA_I2C_CON)) & CON_INTPND) + return true; + else + return false; +} + +static bool sata_i2c_is_tx_ack(void) +{ + if ((__raw_readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_LAST) + return false; + else + return true; +} + +static bool sata_i2c_is_bus_ready(void) +{ + if ((__raw_readl(phy_i2c_base + SATA_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) +{ + clrbits_le32(phy_i2c_base + SATA_I2C_CON, CON_INTPND); +} + +static void sata_i2c_set_ack_gen(bool enable) +{ + if (enable) + setbits_le32(phy_i2c_base + SATA_I2C_CON, CON_ACKEN); + else + clrbits_le32(phy_i2c_base + SATA_I2C_CON, CON_ACKEN); +} + +static void sata_i2c_set_master_tx(void) +{ + /* Disable I2C */ + clrbits_le32(phy_i2c_base + SATA_I2C_STAT, STAT_RTEN); + + /* Clear Mode */ + clrbits_le32(phy_i2c_base + SATA_I2C_STAT, STAT_MSTT); + + sata_i2c_clear_int_status(); + + /* interrupt disable */ + clrbits_le32(phy_i2c_base + SATA_I2C_CON, CON_INTEN); + + /* Master, Send mode */ + setbits_le32(phy_i2c_base + SATA_I2C_STAT, STAT_MSTT); + + /* interrupt enable */ + setbits_le32(phy_i2c_base + SATA_I2C_CON, CON_INTEN); + + /* Enable I2C */ + setbits_le32(phy_i2c_base + SATA_I2C_STAT, STAT_RTEN); +} + +static void sata_i2c_init(void) +{ + clrbits_le32(phy_i2c_base + SATA_I2C_CON, ~CON_CLK16); + clrbits_le32(phy_i2c_base + SATA_I2C_CON, CON_TXCLK_PS); + setbits_le32(phy_i2c_base + SATA_I2C_CON, 2 & CON_TXCLK_PS); + clrbits_le32(phy_i2c_base + SATA_I2C_LC, LC_FLTR_EN); + + sata_i2c_set_ack_gen(false); +} +static bool sata_i2c_send(u8 slave_addrs, u8 addrs, u8 ucData) +{ + s32 ret = 0; + 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_ctrl + SATA_RESET); + sata_i2c_write_addrs(slave_addrs); + sata_i2c_start(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + goto STOP; + } + sata_i2c_write_data(addrs); + sata_i2c_clear_int_status(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + goto STOP; + } + sata_i2c_write_data(ucData); + sata_i2c_clear_int_status(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + 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 __iomem *mmio) +{ + u8 uCount, i = 0; + /* 0x3A for 40bit I/F */ + u8 reg_addrs[] = {0x3A}; + /* 0x0B for 40bit I/F */ + u8 default_setting_value[] = {0x0B}; + + uCount = sizeof(reg_addrs)/sizeof(u8); + while (i < uCount) { + if (!sata_i2c_send(SATA_PHY_I2C_SLAVE_ADDRS, reg_addrs[i], + default_setting_value[i])) + return false; + i++; + } + return true; +} + +static int exynos5_ahci_init(void __iomem *mmio) +{ + int ret; + + if (sata_is_reg(phy_ctrl, SATA_CTRL0, + CTRL0_P0_PHY_CALIBRATED, CTRL0_P0_PHY_CALIBRATED)) + { + printf("%s: already calibrated?\n", __func__); + } + + setbits_le32(EXYNOS5_SATA_PHY_CONTROL, S5P_PMU_SATA_PHY_CONTROL_EN); + + __raw_writel(0, phy_ctrl + SATA_RESET); + setbits_le32(phy_ctrl + SATA_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_ctrl + SATA_RESET, LINK_RESET); + + setbits_le32(phy_ctrl + SATA_RESET, RESET_CMN_RST_N); + + clrbits_le32(phy_ctrl + SATA_PHSATA_CTRLM, PHCTRLM_REF_RATE); + + /* High speed enable for Gen3 */ + setbits_le32(phy_ctrl + SATA_PHSATA_CTRLM, PHCTRLM_HIGH_SPEED); + + setbits_le32(phy_ctrl + SATA_CTRL0, + CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED); + + sata_set_gen(SATA_GENERATION3); + + ret = ahci_phy_init(mmio); + + /* release cmu reset */ + clrbits_le32(phy_ctrl + SATA_RESET, RESET_CMN_RST_N); + + setbits_le32(phy_ctrl + SATA_RESET, RESET_CMN_RST_N); + + if (wait_for_reg_status(phy_ctrl, SATA_PHSATA_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) +{ + exynos5_enable_clock_gates(); + + if (exynos5_ahci_init((void *)SATA_AHCI_AXI)) { + ahci_init(SATA_AHCI_AXI); + return 0; + } + return -ENODEV; +} 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..a181d01 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/sata.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#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 76adaf3..c06af34 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -34,6 +34,7 @@ #include <onenand_uboot.h> #include <mmc.h> #include <scsi.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 83fd3bd..551bfce 100644 --- a/board/samsung/arndale/arndale.c +++ b/board/samsung/arndale/arndale.c @@ -10,6 +10,7 @@ #include <asm/arch/dwmmc.h> #include <asm/arch/gpio.h> #include <asm/arch/power.h> +#include <asm/arch/sata.h> DECLARE_GLOBAL_DATA_PTR; @@ -29,6 +30,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 292729b..e992769 100644 --- a/include/configs/arndale.h +++ b/include/configs/arndale.h @@ -75,6 +75,7 @@ #define CONFIG_SUPPORT_EMMC_BOOT #define CONFIG_BOUNCE_BUFFER +#define CONFIG_EXYNOS5250_AHCI #define CONFIG_BOARD_EARLY_INIT_F #define CONFIG_SKIP_LOWLEVEL_INIT @@ -91,6 +92,17 @@ #define CONFIG_CMD_MMC #define CONFIG_CMD_HASH +#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 + #define CONFIG_ZERO_BOOTDELAY_CHECK /* USB */ @@ -204,6 +216,7 @@ #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 1) \ func(MMC, mmc, 0) \ + func(SCSI, scsi, 0) \ func(PXE, pxe, na) \ func(DHCP, dhcp, na) -- 2.1.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot