mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-07-08 17:56:11 +00:00
ENGR00124256 Linux platform integrated AHCI SATA driver
Sata can work well on EVK boards, and pass the unit-tests. Signed-off-by: Richard Zhu <r65037@freescale.com>
This commit is contained in:
@@ -655,7 +655,7 @@ CONFIG_SCSI_LOWLEVEL=y
|
||||
CONFIG_ATA=m
|
||||
# CONFIG_ATA_NONSTANDARD is not set
|
||||
# CONFIG_SATA_PMP is not set
|
||||
# CONFIG_SATA_AHCI_PLATFORM is not set
|
||||
CONFIG_SATA_AHCI_PLATFORM=m
|
||||
CONFIG_ATA_SFF=y
|
||||
# CONFIG_SATA_MV is not set
|
||||
# CONFIG_PATA_PLATFORM is not set
|
||||
|
||||
@@ -873,6 +873,29 @@ struct platform_device pata_fsl_device = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource ahci_fsl_resources[] = {
|
||||
{
|
||||
.start = MX53_SATA_BASE_ADDR,
|
||||
.end = MX53_SATA_BASE_ADDR + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = MXC_INT_SATA,
|
||||
.end = MXC_INT_SATA,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device ahci_fsl_device = {
|
||||
.name = "ahci",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(ahci_fsl_resources),
|
||||
.resource = ahci_fsl_resources,
|
||||
.dev = {
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
static u64 usb_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct resource usbotg_resources[] = {
|
||||
|
||||
@@ -54,6 +54,7 @@ extern struct platform_device mxc_sim_device;
|
||||
extern struct platform_device mxcsdhc1_device;
|
||||
extern struct platform_device mxcsdhc2_device;
|
||||
extern struct platform_device mxcsdhc3_device;
|
||||
extern struct platform_device ahci_fsl_device;
|
||||
extern struct platform_device pata_fsl_device;
|
||||
extern struct platform_device gpu_device;
|
||||
extern struct platform_device mxc_fec_device;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <linux/mxcfb.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/fec.h>
|
||||
#include <linux/ahci_platform.h>
|
||||
#include <mach/common.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
@@ -523,6 +524,161 @@ static struct mxc_mmc_platform_data mmc3_data = {
|
||||
.clock_mmc = "esdhc_clk",
|
||||
};
|
||||
|
||||
/* return value 1 failure, 0 success */
|
||||
static int write_phy_ctl_ack_polling(u32 data, void __iomem *mmio,
|
||||
int max_iterations, u32 exp_val)
|
||||
{
|
||||
enum {
|
||||
PORT_PHY_CTL = 0x178, /* Port0 PHY Control */
|
||||
PORT_PHY_SR = 0x17c, /* Port0 PHY Status */
|
||||
/* PORT_PHY_SR */
|
||||
PORT_PHY_STAT_DATA_LOC = 0,
|
||||
PORT_PHY_STAT_ACK_LOC = 18,
|
||||
};
|
||||
int i;
|
||||
u32 val;
|
||||
|
||||
writel(data, mmio + PORT_PHY_CTL);
|
||||
|
||||
for (i = 0; i < max_iterations + 1; i++) {
|
||||
val = readl(mmio + PORT_PHY_SR);
|
||||
val = (val >> PORT_PHY_STAT_ACK_LOC) & 0x1;
|
||||
if (val == exp_val)
|
||||
return 0;
|
||||
if (i == max_iterations) {
|
||||
printk(KERN_ERR "Wait for CR ACK error!\n");
|
||||
return 1;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HW Initialization, if return 1, initialization is failed. */
|
||||
static int sata_init(struct device *dev)
|
||||
{
|
||||
enum {
|
||||
HOST_CAP = 0x00,
|
||||
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
|
||||
HOST_PORTS_IMPL = 0x0c,
|
||||
HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
|
||||
/* Offest used to control the MPLL input clk */
|
||||
PHY_CR_CLOCK_FREQ_OVRD = 0x12,
|
||||
|
||||
PORT_PHY_CTL = 0x178, /* Port0 PHY Control */
|
||||
/* PORT_PHY_CTL bits */
|
||||
PORT_PHY_CTL_CAP_ADR_LOC = 0x10000,
|
||||
PORT_PHY_CTL_CAP_DAT_LOC = 0x20000,
|
||||
PORT_PHY_CTL_WRITE_LOC = 0x40000,
|
||||
};
|
||||
void __iomem *mmio;
|
||||
struct clk *clk;
|
||||
int rc = 0;
|
||||
u32 tmpdata;
|
||||
|
||||
clk = clk_get(dev, "sata_clk");
|
||||
clk_enable(clk);
|
||||
|
||||
mmio = ioremap(MX53_SATA_BASE_ADDR, SZ_4K);
|
||||
|
||||
tmpdata = readl(mmio + HOST_CAP);
|
||||
if (!(tmpdata & HOST_CAP_SSS)) {
|
||||
tmpdata |= HOST_CAP_SSS;
|
||||
writel(tmpdata, mmio + HOST_CAP);
|
||||
}
|
||||
|
||||
if (!(readl(mmio + HOST_PORTS_IMPL) & 0x1))
|
||||
writel((readl(mmio + HOST_PORTS_IMPL) | 0x1),
|
||||
mmio + HOST_PORTS_IMPL);
|
||||
|
||||
/* Get the AHB clock rate, and configure the TIMER1MS reg */
|
||||
clk = clk_get(NULL, "ahb_clk");
|
||||
tmpdata = clk_get_rate(clk) / 1000;
|
||||
writel(tmpdata, mmio + HOST_TIMER1MS);
|
||||
|
||||
/* write addr */
|
||||
tmpdata = PHY_CR_CLOCK_FREQ_OVRD;
|
||||
writel(tmpdata, mmio + PORT_PHY_CTL);
|
||||
/* capture addr */
|
||||
tmpdata |= PORT_PHY_CTL_CAP_ADR_LOC;
|
||||
/* Wait for ack */
|
||||
if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 1)) {
|
||||
rc = 1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* deassert cap data */
|
||||
tmpdata &= 0xFFFF;
|
||||
/* wait for ack de-assertion */
|
||||
if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 0)) {
|
||||
rc = 1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* write data */
|
||||
/* Configure the PHY CLK input refer to different OSC
|
||||
* For 25MHz, pre[13,14]:01, ncy[12,8]:06,
|
||||
* ncy5[7,6]:02, int_ctl[5,3]:0, prop_ctl[2,0]:7.
|
||||
* For 50MHz, pre:00, ncy:06, ncy5:02, int_ctl:0, prop_ctl:7.
|
||||
*/
|
||||
/* EVK revA */
|
||||
if (board_is_mx53_evk_a())
|
||||
tmpdata = (0x1 << 15) | (0x1 << 13) | (0x6 << 8)
|
||||
| (0x2 << 6) | 0x7;
|
||||
/* EVK revB */
|
||||
else if (board_is_mx53_evk_b())
|
||||
tmpdata = (0x1 << 15) | (0x0 << 13) | (0x6 << 8)
|
||||
| (0x2 << 6) | 0x7;
|
||||
|
||||
writel(tmpdata, mmio + PORT_PHY_CTL);
|
||||
/* capture data */
|
||||
tmpdata |= PORT_PHY_CTL_CAP_DAT_LOC;
|
||||
/* wait for ack */
|
||||
if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 1)) {
|
||||
rc = 1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* deassert cap data */
|
||||
tmpdata &= 0xFFFF;
|
||||
/* wait for ack de-assertion */
|
||||
if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 0)) {
|
||||
rc = 1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* assert wr signal and wait for ack */
|
||||
if (write_phy_ctl_ack_polling(PORT_PHY_CTL_WRITE_LOC, mmio, 100, 1)) {
|
||||
rc = 1;
|
||||
goto err0;
|
||||
}
|
||||
/* deassert rd _signal and wait for ack de-assertion */
|
||||
if (write_phy_ctl_ack_polling(0, mmio, 100, 0)) {
|
||||
rc = 1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
msleep(10);
|
||||
|
||||
err0:
|
||||
iounmap(mmio);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void sata_exit(struct device *dev)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_get(dev, "sata_clk");
|
||||
clk_disable(clk);
|
||||
clk_put(clk);
|
||||
}
|
||||
|
||||
static struct ahci_platform_data sata_data = {
|
||||
.init = sata_init,
|
||||
.exit = sata_exit,
|
||||
};
|
||||
|
||||
static int mxc_sgtl5000_amp_enable(int enable)
|
||||
{
|
||||
/* TO DO */
|
||||
@@ -808,6 +964,7 @@ static void __init mxc_board_init(void)
|
||||
mxc_register_device(&mxcsdhc3_device, &mmc3_data);
|
||||
mxc_register_device(&mxc_ssi1_device, NULL);
|
||||
mxc_register_device(&mxc_ssi2_device, NULL);
|
||||
mxc_register_device(&ahci_fsl_device, &sata_data);
|
||||
mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data);
|
||||
|
||||
mxc_register_device(&mxc_fec_device, &fec_data);
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#define BOARD_REV_1 0x000
|
||||
#define BOARD_REV_2 0x100
|
||||
#define BOARD_REV_3 0x200
|
||||
|
||||
#ifdef CONFIG_ARCH_MX3
|
||||
#include <mach/mx3x.h>
|
||||
@@ -85,6 +86,8 @@ extern unsigned int system_rev;
|
||||
|
||||
#ifdef CONFIG_ARCH_MX5
|
||||
#define board_is_mx53_arm2() (cpu_is_mx53() && board_is_rev(BOARD_REV_2))
|
||||
#define board_is_mx53_evk_a() (cpu_is_mx53() && board_is_rev(BOARD_REV_1))
|
||||
#define board_is_mx53_evk_b() (cpu_is_mx53() && board_is_rev(BOARD_REV_3))
|
||||
#endif
|
||||
|
||||
#include <mach/mxc.h>
|
||||
|
||||
@@ -127,6 +127,11 @@
|
||||
#define MX51_TZIC_BASE_ADDR 0xE0000000
|
||||
#define TZIC_SIZE SZ_16K
|
||||
|
||||
/*
|
||||
* AHCI SATA
|
||||
*/
|
||||
#define MX53_SATA_BASE_ADDR 0x10000000
|
||||
|
||||
#define DEBUG_BASE_ADDR 0x40000000
|
||||
/*MX53 + 0x2000000 */
|
||||
#define DEBUG_SIZE SZ_1M
|
||||
|
||||
Reference in New Issue
Block a user