summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2010-11-19 16:54:08 +0800
committerRichard Zhu <r65037@freescale.com>2010-12-03 11:19:13 +0800
commitb8f7e567ce97503ee3c4c908ac01178f7f359f7c (patch)
tree8f0a4c1151d962b83c4e0c1a59bb115eb2d8f2e5
parentcb695684ced4d4b83d219a7eb4294c4421528ce6 (diff)
ENGR00134041 [MX53] Add the SATA AHCI temperature monitor
SATA AHCI temperature monitor HOWTO-USE: Use the following cmd after boot up the target board and log in the system The unit of the temperature is celsius. Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r--arch/arm/mach-mx5/devices.h1
-rw-r--r--arch/arm/mach-mx5/mx53_ard.c149
-rw-r--r--arch/arm/mach-mx5/mx53_evk.c158
-rw-r--r--arch/arm/plat-mxc/Makefile1
-rw-r--r--arch/arm/plat-mxc/ahci_sata.c467
5 files changed, 469 insertions, 307 deletions
diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h
index c011f0905a6a..2337d46982c0 100644
--- a/arch/arm/mach-mx5/devices.h
+++ b/arch/arm/mach-mx5/devices.h
@@ -64,6 +64,7 @@ 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 ahci_platform_data sata_data;
extern struct platform_device pata_fsl_device;
extern struct platform_device fsl_otp_device;
extern struct platform_device gpu_device;
diff --git a/arch/arm/mach-mx5/mx53_ard.c b/arch/arm/mach-mx5/mx53_ard.c
index 960c31cbf719..470a4638afbe 100644
--- a/arch/arm/mach-mx5/mx53_ard.c
+++ b/arch/arm/mach-mx5/mx53_ard.c
@@ -45,7 +45,6 @@
#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>
@@ -933,154 +932,6 @@ static struct mxc_mmc_platform_data mmc2_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_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, "imx_sata_clk");
- if (IS_ERR(clk))
- printk(KERN_ERR "IMX SATA can't get clock.\n");
- 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 50MHz, pre:00, ncy:06, ncy5:02, int_ctl:0, prop_ctl:7.
- */
- 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, "imx_sata_clk");
- clk_disable(clk);
- clk_put(clk);
-}
-
-static struct ahci_platform_data sata_data = {
- .init = sata_init,
- .exit = sata_exit,
-};
-
static struct resource ard_smsc911x_resources[] = {
{
.start = MX53_CS1_BASE_ADDR,
diff --git a/arch/arm/mach-mx5/mx53_evk.c b/arch/arm/mach-mx5/mx53_evk.c
index e61cf16f482e..4fb451b380bc 100644
--- a/arch/arm/mach-mx5/mx53_evk.c
+++ b/arch/arm/mach-mx5/mx53_evk.c
@@ -43,7 +43,6 @@
#include <linux/mxcfb.h>
#include <linux/pwm_backlight.h>
#include <linux/fec.h>
-#include <linux/ahci_platform.h>
#include <linux/powerkey.h>
#include <mach/common.h>
#include <mach/hardware.h>
@@ -1131,163 +1130,6 @@ 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, "imx_sata_clk");
- if (IS_ERR(clk))
- printk(KERN_ERR "IMX SATA can't get clock.\n");
- 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, "imx_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 */
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index c935fd46741b..4319b330b691 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -35,6 +35,7 @@ endif
obj-$(CONFIG_ARCH_MX37) += dptc.o dvfs_core.o
obj-$(CONFIG_ARCH_MX5) += dvfs_core.o
+obj-$(CONFIG_ARCH_MX5) += ahci_sata.o
# CPU FREQ support
obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
diff --git a/arch/arm/plat-mxc/ahci_sata.c b/arch/arm/plat-mxc/ahci_sata.c
new file mode 100644
index 000000000000..113b121cbbf8
--- /dev/null
+++ b/arch/arm/plat-mxc/ahci_sata.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/ahci_platform.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+
+/*****************************************************************************\
+ * *
+ * FSL SATA AHCI low level functions *
+ * return value 1 failure, 0 success *
+ * *
+\*****************************************************************************/
+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,
+ /* Port0 PHY Control */
+ PORT_PHY_CTL = 0x178,
+ /* PORT_PHY_CTL bits */
+ PORT_PHY_CTL_CAP_ADR_LOC = 0x10000,
+ PORT_PHY_CTL_CAP_DAT_LOC = 0x20000,
+ PORT_PHY_CTL_WRITE_LOC = 0x40000,
+ PORT_PHY_CTL_READ_LOC = 0x80000,
+ /* Port0 PHY Status */
+ PORT_PHY_SR = 0x17c,
+ /* PORT_PHY_SR */
+ PORT_PHY_STAT_DATA_LOC = 0,
+ PORT_PHY_STAT_ACK_LOC = 18,
+ /* SATA PHY Register */
+ SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT = 0x0001,
+ SATA_PHY_CR_CLOCK_DAC_CTL = 0x0008,
+ SATA_PHY_CR_CLOCK_RTUNE_CTL = 0x0009,
+ SATA_PHY_CR_CLOCK_ADC_OUT = 0x000A,
+ SATA_PHY_CR_CLOCK_MPLL_TST = 0x0017,
+};
+
+static int write_phy_ctl_ack_polling(u32 data, void __iomem *mmio,
+ int max_iterations, u32 exp_val)
+{
+ u32 i, 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;
+}
+
+static int sata_phy_cr_addr(u32 addr, void __iomem *mmio)
+{
+ u32 temp_wr_data;
+
+ /* write addr */
+ temp_wr_data = addr;
+ writel(temp_wr_data, mmio + PORT_PHY_CTL);
+
+ /* capture addr */
+ temp_wr_data |= PORT_PHY_CTL_CAP_ADR_LOC;
+
+ /* wait for ack */
+ if (write_phy_ctl_ack_polling(temp_wr_data, mmio, 100, 1))
+ return 1;
+
+ /* deassert cap addr */
+ temp_wr_data &= 0xffff;
+
+ /* wait for ack de-assetion */
+ if (write_phy_ctl_ack_polling(temp_wr_data, mmio, 100, 0))
+ return 1;
+
+ return 0;
+}
+
+static int sata_phy_cr_write(u32 data, void __iomem *mmio)
+{
+ u32 temp_wr_data;
+
+ /* write data */
+ temp_wr_data = data;
+
+ /* capture data */
+ temp_wr_data |= PORT_PHY_CTL_CAP_DAT_LOC;
+
+ /* wait for ack */
+ if (write_phy_ctl_ack_polling(temp_wr_data, mmio, 100, 1))
+ return 1;
+
+ /* deassert cap data */
+ temp_wr_data &= 0xffff;
+
+ /* wait for ack de-assetion */
+ if (write_phy_ctl_ack_polling(temp_wr_data, mmio, 100, 0))
+ return 1;
+
+ /* assert wr signal */
+ temp_wr_data |= PORT_PHY_CTL_WRITE_LOC;
+
+ /* wait for ack */
+ if (write_phy_ctl_ack_polling(temp_wr_data, mmio, 100, 1))
+ return 1;
+
+ /* deassert wr _signal */
+ temp_wr_data = 0x0;
+
+ /* wait for ack de-assetion */
+ if (write_phy_ctl_ack_polling(temp_wr_data, mmio, 100, 0))
+ return 1;
+
+ return 0;
+}
+
+static int sata_phy_cr_read(u32 *data, void __iomem *mmio)
+{
+ u32 temp_rd_data, temp_wr_data;
+
+ /* assert rd signal */
+ temp_wr_data = PORT_PHY_CTL_READ_LOC;
+
+ /* wait for ack */
+ if (write_phy_ctl_ack_polling(temp_wr_data, mmio, 100, 1))
+ return 1;
+
+ /* after got ack return data */
+ temp_rd_data = readl(mmio + PORT_PHY_SR);
+ *data = (temp_rd_data & 0xffff);
+
+ /* deassert rd _signal */
+ temp_wr_data = 0x0 ;
+
+ /* wait for ack de-assetion */
+ if (write_phy_ctl_ack_polling(temp_wr_data, mmio, 100, 0))
+ return 1;
+
+ return 0;
+}
+
+/* SATA AHCI temperature monitor */
+static ssize_t sata_ahci_current_tmp(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ void __iomem *mmio;
+ u32 mpll_test_reg, rtune_ctl_reg, dac_ctl_reg, adc_out_reg;
+ u32 str1, str2, str3, str4, read_sum, index;
+ int m1, m2, a, temp;
+
+ /* map the IO addr */
+ mmio = ioremap(MX53_SATA_BASE_ADDR, SZ_2K);
+ if (mmio == NULL) {
+ printk(KERN_ERR "Failed to map SATA REGS\n");
+ return 1;
+ }
+
+ /* check rd-wr to reg */
+ read_sum = 0;
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT, mmio);
+ sata_phy_cr_write(read_sum, mmio);
+ sata_phy_cr_read(&read_sum, mmio);
+ if ((read_sum & 0xffff) != 0)
+ printk(KERN_ERR "Read/Write REG error, 0x%x!\n", read_sum);
+
+ sata_phy_cr_write(0x5A5A, mmio);
+ sata_phy_cr_read(&read_sum, mmio);
+ if ((read_sum & 0xffff) != 0x5A5A)
+ printk(KERN_ERR "Read/Write REG error, 0x%x!\n", read_sum);
+
+ sata_phy_cr_write(0x1234, mmio);
+ sata_phy_cr_read(&read_sum, mmio);
+ if ((read_sum & 0xffff) != 0x1234)
+ printk(KERN_ERR "Read/Write REG error, 0x%x!\n", read_sum);
+
+ /* stat temperature test */
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+ sata_phy_cr_read(&mpll_test_reg, mmio);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+ sata_phy_cr_read(&rtune_ctl_reg, mmio);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+ sata_phy_cr_read(&dac_ctl_reg, mmio);
+
+ /* mpll_tst.meas_iv ([12:2]) */
+ str1 = (mpll_test_reg >> 2) & 0x7FF;
+ /* rtune_ctl.mode ([1:0]) */
+ str2 = (rtune_ctl_reg) & 0x3;
+ /* dac_ctl.dac_mode ([14:12]) */
+ str3 = (dac_ctl_reg >> 12) & 0x7;
+ /* rtune_ctl.sel_atbp ([4]) */
+ str4 = (rtune_ctl_reg >> 4);
+
+ /* Caculate the m1 */
+ /* mpll_tst.meas_iv */
+ mpll_test_reg = (mpll_test_reg & 0xE03) | (512) << 2;
+ /* rtune_ctl.mode */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (1);
+ /* dac_ctl.dac_mode */
+ dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (4) << 12;
+ /* rtune_ctl.sel_atbp */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (0) << 4;
+
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+ sata_phy_cr_write(mpll_test_reg, mmio);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+ sata_phy_cr_write(dac_ctl_reg, mmio);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+ sata_phy_cr_write(rtune_ctl_reg, mmio);
+
+ /* two dummy read */
+ index = 0;
+ read_sum = 0;
+ adc_out_reg = 0;
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_ADC_OUT, mmio);
+ while (index < 2) {
+ sata_phy_cr_read(&adc_out_reg, mmio);
+ /* check if valid */
+ if (adc_out_reg & 0x400)
+ index = index + 1;
+ read_sum++;
+ if (read_sum > 100000) {
+ printk(KERN_ERR "Read REG more than 100000 times!\n");
+ break;
+ }
+ }
+
+ index = 0;
+ read_sum = 0;
+ while (index < 80) {
+ sata_phy_cr_read(&adc_out_reg, mmio);
+ if (adc_out_reg & 0x400) {
+ read_sum = read_sum + (adc_out_reg & 0x3FF);
+ index = index + 1;
+ }
+ }
+ /* Use the U32 to make 1000 precision */
+ m1 = (read_sum * 1000) / 80;
+
+ /* Caculate the m2 */
+ /* rtune_ctl.sel_atbp */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (1) << 4;
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+ sata_phy_cr_write(rtune_ctl_reg, mmio);
+
+ /* two dummy read */
+ index = 0;
+ read_sum = 0;
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_ADC_OUT, mmio);
+ while (index < 2) {
+ sata_phy_cr_read(&adc_out_reg, mmio);
+ /* check if valid */
+ if (adc_out_reg & 0x400)
+ index = index + 1;
+ read_sum++;
+ if (read_sum > 100000) {
+ printk(KERN_ERR "Read REG more than 100000 times!\n");
+ break;
+ }
+ }
+
+ index = 0;
+ read_sum = 0;
+ while (index < 80) {
+ /* FIX ME dead loop protection??? */
+ sata_phy_cr_read(&adc_out_reg, mmio);
+ if (adc_out_reg & 0x400) {
+ read_sum = read_sum + (adc_out_reg & 0x3FF);
+ index = index + 1;
+ }
+ }
+ /* Use the U32 to make 1000 precision */
+ m2 = (read_sum * 1000) / 80;
+
+ /* restore the status */
+ /* mpll_tst.meas_iv */
+ mpll_test_reg = (mpll_test_reg & 0xE03) | (str1) << 2;
+ /* rtune_ctl.mode */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (str2);
+ /* dac_ctl.dac_mode */
+ dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (str3) << 12;
+ /* rtune_ctl.sel_atbp */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (str4) << 4;
+
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+ sata_phy_cr_write(mpll_test_reg, mmio);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+ sata_phy_cr_write(dac_ctl_reg, mmio);
+ sata_phy_cr_addr(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+ sata_phy_cr_write(rtune_ctl_reg, mmio);
+
+ /* Compute temperature */
+ if (!(m2 / 1000))
+ m2 = 1000;
+ a = (m2 - m1) / (m2 / 1000);
+ temp = ((((-559) * a) / 1000) * a) / 1000 + (1379) * a / 1000 + (-458);
+
+ iounmap(mmio);
+ return sprintf(buf, "SATA AHCI current temperature:%d\n", temp);
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, sata_ahci_current_tmp, NULL);
+
+static struct attribute *fsl_sata_ahci_attr[] = {
+ &dev_attr_temperature.attr,
+ NULL
+};
+
+static const struct attribute_group fsl_sata_ahci_group = {
+ .attrs = fsl_sata_ahci_attr,
+};
+
+/* HW Initialization, if return 1, initialization is failed. */
+static int sata_init(struct device *dev)
+{
+ void __iomem *mmio;
+ struct clk *clk;
+ int ret, rc = 0;
+ u32 tmpdata;
+
+ clk = clk_get(dev, "imx_sata_clk");
+ if (IS_ERR(clk))
+ printk(KERN_ERR "IMX SATA can't get clock.\n");
+ clk_enable(clk);
+
+ mmio = ioremap(MX53_SATA_BASE_ADDR, SZ_2K);
+ if (mmio == NULL) {
+ printk(KERN_ERR "Failed to map SATA REGS\n");
+ return 1;
+ }
+
+ 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");
+ if (IS_ERR(clk))
+ printk(KERN_ERR "IMX SATA can't get AHB clock.\n");
+ 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;
+ /* Others are 50MHz */
+ else
+ 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);
+
+ /* Add the temperature monitor */
+ ret = sysfs_create_group(&dev->kobj, &fsl_sata_ahci_group);
+ if (ret)
+ sysfs_remove_group(&dev->kobj, &fsl_sata_ahci_group);
+
+err0:
+ iounmap(mmio);
+ return rc;
+}
+
+static void sata_exit(struct device *dev)
+{
+ struct clk *clk;
+
+ sysfs_remove_group(&dev->kobj, &fsl_sata_ahci_group);
+ clk = clk_get(dev, "imx_sata_clk");
+ if (IS_ERR(clk))
+ printk(KERN_ERR "IMX SATA can't get clock.\n");
+ clk_disable(clk);
+ clk_put(clk);
+}
+
+struct ahci_platform_data sata_data = {
+ .init = sata_init,
+ .exit = sata_exit,
+};
+