[U-Boot] [PATCH v2] exynos5250/arndale: Enable SATA/AHCI support.

Ian Campbell ian.campbell at citrix.com
Mon Dec 8 15:54:40 CET 2014


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 at 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 at 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 at 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.
 - 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 at citrix.com>
Cc: Taylor Hutt <thutt at chromium.org>
Cc: Simon Glass <sjg at 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 */
+};
+
+/* 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)
 
-- 
2.1.1



More information about the U-Boot mailing list