/* * STMicroelectronics MiPHY driver * * Copyright (C) 2009 STMicroelectronics Limited * Author: Pawel Moll * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ #include #include #include #include #include #include #include #include #include "miphy.h" #define MIPHY_RESET 0x00 #define RST_RX (1<<4) #define MIPHY_STATUS 0x01 #define MIPHY_CONTROL 0x02 #define DIS_LINK_RST (1<<4) #define MIPHY_INT_STATUS 0x04 #define BITUNLOCK_INT (1<<1) #define SYMBUNLOCK_INT (1<<2) #define FIFOOVERLAP_INT (1<<3) #define MIPHY_BOUNDARY_1 0x10 #define POWERSEL_SEL (1<<2) #define SPDSEL_SEL (1<<0) #define MIPHY_BOUNDARY_3 0x12 #define RX_LSPD (1<<5) #define MIPHY_COMPENS_CONTROL_1 0x40 #define MIPHY_IDLL_TEST 0x72 #define START_CLK_HF (1<<6) #define STOP_CLK_HF (1<<7) #define MIPHY_DES_BITLOCK_CFG 0x85 #define CLEAR_BIT_UNLOCK_FLAG (1<<0) #define UPDATE_TRANS_DENSITY (1<<1) #define MIPHY_DES_BITLOCK 0x86 #define MIPHY_DES_BITLOCK_STATUS 0x88 #define BIT_LOCK (1<<0) #define BIT_LOCK_FAILED (1<<1) #define BIT_UNLOCK (1<<2) #define TRANS_DENSITY_UPDATED (1<<3) #define MIPHY_VERSION 0xfb #define MIPHY_REVISION 0xfc static struct class *miphy_class; static DEFINE_MUTEX(miphy_list_mutex); static LIST_HEAD(miphy_list); struct stm_miphy { struct stm_miphy_device *dev; int port; enum miphy_mode mode; struct list_head node; struct device *owner; struct device *device; }; /* Start functions for miphy port * Ideally all the start functions should be identical, however * they tend to be different in physical arrangement. * The physicall (IP) arrangement lead to different start functions. */ /* * MiPhy Port 0 Start function for SATA */ static void tap_miphy_start_port0(const struct miphy_if_ops *ops) { int timeout; void (*reg_write)(int port, u8 addr, u8 data) = ops->reg_write; u8 (*reg_read)(int port, u8 addr) = ops->reg_read; /* TODO: Get rid of this */ if (cpu_data->type == CPU_STX7108) { /*Force SATA port 1 in Slumber Mode */ reg_write(1, 0x11, 0x8); /*Force Power Mode selection from MiPHY soft register 0x11 */ reg_write(1, 0x10, 0x4); } /* Force Macro1 in reset and request PLL calibration reset */ /* Force PLL calibration reset, PLL reset and assert * Deserializer Reset */ reg_write(0, 0x00, 0x16); reg_write(0, 0x11, 0x0); /* Force macro1 to use rx_lspd, tx_lspd (by default rx_lspd * and tx_lspd set for Gen1) */ reg_write(0, 0x10, 0x1); /* Force Recovered clock on first I-DLL phase & all * Deserializers in HP mode */ /* Force Rx_Clock on first I-DLL phase on macro1 */ reg_write(0, 0x72, 0x40); /* Force Des in HP mode on macro1 */ reg_write(0, 0x12, 0x00); /* Wait for HFC_READY = 0 */ timeout = 50; /* Jeeeezzzzz.... */ while (timeout-- && (reg_read(0, 0x01) & 0x3)) udelay(2000); if (timeout < 0) pr_err("%s(): HFC_READY timeout!\n", __func__); /* Restart properly Process compensation & PLL Calibration */ /* Set properly comsr definition for 30 MHz ref clock */ reg_write(0, 0x41, 0x1E); /* comsr compensation reference */ reg_write(0, 0x42, 0x28); /* Set properly comsr definition for 30 MHz ref clock */ reg_write(0, 0x41, 0x1E); /* comsr cal gives more suitable results in fast PVT for comsr used by TX buffer to build slopes making TX rise/fall fall times. */ reg_write(0, 0x42, 0x33); /* Force VCO current to value defined by address 0x5A */ reg_write(0, 0x51, 0x2); /* Force VCO current to value defined by address 0x5A */ reg_write(0, 0x5A, 0xF); /* Enable auto load compensation for pll_i_bias */ reg_write(0, 0x47, 0x2A); /* Force restart compensation and enable auto load for * Comzc_Tx, Comzc_Rx & Comsr on macro1 */ reg_write(0, 0x40, 0x13); /* Wait for comzc & comsr done */ while ((reg_read(0, 0x40) & 0xC) != 0xC) cpu_relax(); /* Recommended settings for swing & slew rate FOR SATA GEN 1 * from CPG */ reg_write(0, 0x20, 0x00); /* (Tx Swing target 500-550mV peak-to-peak diff) */ reg_write(0, 0x21, 0x2); /* (Tx Slew target120-140 ps rising/falling time) */ reg_write(0, 0x22, 0x4); /* Force Macro1 in partial mode & release pll cal reset */ reg_write(0, 0x00, 0x10); udelay(10); #if 0 /* SSC Settings. SSC will be enabled through Link */ reg_write(0, 0x53, 0x00); /* pll_offset */ reg_write(0, 0x54, 0x00); /* pll_offset */ reg_write(0, 0x55, 0x00); /* pll_offset */ reg_write(0, 0x56, 0x04); /* SSC Ampl=0.48% */ reg_write(0, 0x57, 0x11); /* SSC Ampl=0.48% */ reg_write(0, 0x58, 0x00); /* SSC Freq=31KHz */ reg_write(0, 0x59, 0xF1); /* SSC Freq=31KHz */ /*SSC Settings complete*/ #endif reg_write(0, 0x50, 0x8D); reg_write(0, 0x50, 0x8D); /* Wait for phy_ready */ /* When phy is in ready state ( register 0x01 of macro1 to 0x13) */ while ((reg_read(0, 0x01) & 0x03) != 0x03) cpu_relax(); /* Enable macro1 to use rx_lspd & tx_lspd from link interface */ reg_write(0, 0x10, 0x00); /* Release Rx_Clock on first I-DLL phase on macro1 */ reg_write(0, 0x72, 0x00); /* Deassert deserializer reset */ reg_write(0, 0x00, 0x00); /* des_bit_lock_en is set */ reg_write(0, 0x02, 0x08); /* bit lock detection strength */ reg_write(0, 0x86, 0x61); } /* * MiPhy Port 1 Start function for SATA */ static void tap_miphy_start_port1(const struct miphy_if_ops *ops) { int timeout; void (*reg_write)(int port, u8 addr, u8 data) = ops->reg_write; u8 (*reg_read)(int port, u8 addr) = ops->reg_read; /* Force PLL calibration reset, PLL reset and assert Deserializer * Reset */ reg_write(1, 0x00, 0x2); /* Force restart compensation and enable auto load for Comzc_Tx, * Comzc_Rx & Comsr on macro2 */ reg_write(1, 0x40, 0x13); /* Force PLL reset */ reg_write(0, 0x00, 0x2); /* Set properly comsr definition for 30 MHz ref clock */ reg_write(0, 0x41, 0x1E); /* to get more optimum result on comsr calibration giving faster * rise/fall time in SATA spec Gen1 useful for some corner case.*/ reg_write(0, 0x42, 0x33); /* Force restart compensation and enable auto load for Comzc_Tx, * Comzc_Rx & Comsr on macro1 */ reg_write(0, 0x40, 0x13); /*Wait for HFC_READY = 0*/ timeout = 50; /* Jeeeezzzzz.... */ while (timeout-- && (reg_read(0, 0x01) & 0x3)) udelay(2000); if (timeout < 0) pr_err("%s(): HFC_READY timeout!\n", __func__); reg_write(1, 0x11, 0x0); /* Force macro2 to use rx_lspd, tx_lspd (by default rx_lspd and * tx_lspd set for Gen1) */ reg_write(1, 0x10, 0x1); /* Force Rx_Clock on first I-DLL phase on macro2*/ reg_write(1, 0x72, 0x40); /* Force Des in HP mode on macro2 */ reg_write(1, 0x12, 0x00); while ((reg_read(1, 0x40) & 0xC) != 0xC) cpu_relax(); /*RECOMMENDED SETTINGS for Swing & slew rate FOR SATA GEN 1 from CPG*/ reg_write(1, 0x20, 0x00); /*(Tx Swing target 500-550mV peak-to-peak diff) */ reg_write(1, 0x21, 0x2); /*(Tx Slew target120-140 ps rising/falling time) */ reg_write(1, 0x22, 0x4); /*Force Macr21 in partial mode & release pll cal reset */ reg_write(1, 0x00, 0x10); udelay(10); /* Release PLL reset */ reg_write(0, 0x00, 0x0); /* Wait for phy_ready */ /* When phy is in ready state ( register 0x01 of macro1 to 0x13)*/ while ((reg_read(1, 0x01) & 0x03) != 0x03) cpu_relax(); /* Enable macro1 to use rx_lspd & tx_lspd from link interface */ reg_write(1, 0x10, 0x00); /* Release Rx_Clock on first I-DLL phase on macro1 */ reg_write(1, 0x72, 0x00); /* Deassert deserializer reset */ reg_write(1, 0x00, 0x00); /*des_bit_lock_en is set */ reg_write(1, 0x02, 0x08); /*bit lock detection strength */ reg_write(1, 0x86, 0x61); } static int tap_miphy_sata_start(int port, struct stm_miphy_device *miphy_dev) { int rval = 0; switch (port) { case 0: tap_miphy_start_port0(miphy_dev->ops); break; case 1: tap_miphy_start_port1(miphy_dev->ops); break; default: rval = -EINVAL; } return rval; } static int tap_miphy_pcie_start(int port, struct stm_miphy_device *miphy_dev) { /* The tap interface versions do not support PCIE */ return -1; } /* * MiPhy Port 0 & 1 Start function for SATA * only for 7108 CUT2 */ static int mp_miphy_sata_start(int port, struct stm_miphy_device *miphy_dev) { unsigned int regvalue; int timeout; void (*reg_write)(int port, u8 addr, u8 data); u8 (*reg_read)(int port, u8 addr); if (port < 0 || port > 1) return -EINVAL; reg_write = miphy_dev->ops->reg_write; reg_read = miphy_dev->ops->reg_read; /* Force PLL calibration reset, PLL reset * and assert Deserializer Reset */ reg_write(port, 0x00, 0x16); reg_write(port, 0x11, 0x0); /* Force macro1 to use rx_lspd, tx_lspd * (by default rx_lspd and tx_lspd set for Gen1) */ reg_write(port, 0x10, 0x1); /* Force Rx_Clock on first I-DLL phase on macro1 */ reg_write(port, 0x72, 0x40); /* Force Des in HP mode on macro1 */ reg_write(port, 0x12, 0x00); /*Wait for HFC_READY = 0*/ timeout = 50; while (timeout-- && (reg_read(port, 0x01) & 0x3)) udelay(2000); if (timeout < 0) pr_err("%s(): HFC_READY timeout!\n", __func__); /*Set properly comsr definition for 30 MHz ref clock */ reg_write(port, 0x41, 0x1E); /*Set properly comsr definition for 30 MHz ref clock */ reg_write(port, 0x42, 0x33); /* Force VCO current to value defined by address 0x5A * and disable PCIe100Mref bit */ reg_write(port, 0x51, 0x2); /* Enable auto load compensation for pll_i_bias */ reg_write(port, 0x47, 0x2A); /* Force restart compensation and enable auto load for * Comzc_Tx, Comzc_Rx & Comsr on macro1 */ reg_write(port, 0x40, 0x13); while ((reg_read(port, 0x40) & 0xC) != 0xC) cpu_relax(); /* STOS_SemaphoreWait(MiPHY_Int); Wait for Compensation * Completion Interrupt : Not using MiPHY Interrupt for now */ /* Recommended Settings for Swing & slew rate FOR SATA GEN 1 from CCI * conf gen sel = 00b to program Gen1 banked registers & * VDDT filter ON */ reg_write(port, 0x20, 0x10); /*(Tx Swing target 500-550mV peak-to-peak diff) */ reg_write(port, 0x21, 0x3); /*(Tx Slew target120-140 ps rising/falling time) */ reg_write(port, 0x22, 0x4); /*Force Macro1 in partial mode & release pll cal reset */ reg_write(port, 0x00, 0x10); udelay(100); /* SSC Settings. SSC will be enabled through Link */ /* pll_offset */ reg_write(port, 0x53, 0x00); /* pll_offset */ reg_write(port, 0x54, 0x00); /* pll_offset */ reg_write(port, 0x55, 0x00); /* SSC Ampl.=0.4% */ reg_write(port, 0x56, 0x03); /* SSC Ampl.=0.4% */ reg_write(port, 0x57, 0x63); /* SSC Freq=31KHz */ reg_write(port, 0x58, 0x00); /* SSC Freq=31KHz */ reg_write(port, 0x59, 0xF1); /*SSC Settings complete*/ reg_write(port, 0x50, 0x8D); /*MIPHY PLL ratio */ reg_read(port, 0x52); /* Wait for phy_ready */ /* When phy is in ready state ( register 0x01 reads 0x13)*/ regvalue = reg_read(port, 0x01); timeout = 50; while (timeout-- && ((regvalue & 0x03) != 0x03)) { regvalue = reg_read(port, 0x01); udelay(2000); } if (timeout < 0) pr_err("%s(): HFC_READY timeout!\n", __func__); if ((regvalue & 0x03) == 0x03) { /* Enable macro1 to use rx_lspd & * tx_lspd from link interface */ reg_write(port, 0x10, 0x00); /* Release Rx_Clock on first I-DLL phase on macro1 */ reg_write(port, 0x72, 0x00); /* Assert deserializer reset */ reg_write(port, 0x00, 0x10); /* des_bit_lock_en is set */ reg_write(port, 0x02, 0x08); /* bit lock detection strength */ reg_write(port, 0x86, 0x61); /* Deassert deserializer reset */ reg_write(port, 0x00, 0x00); } return 0; } static int mp_miphy_pcie_start(int port, struct stm_miphy_device *miphy_dev) { /* The hardware sets everything up for us, so far nothing to do here */ return 0; } /**************************************************************************** * MiPHY Generic functions available for other drivers */ static void stm_miphy_write(struct stm_miphy *miphy, u8 addr, u8 data) { struct stm_miphy_device *dev = miphy->dev; int port = miphy->port; dev->ops->reg_write(port, addr, data); } static u8 stm_miphy_read(struct stm_miphy *miphy, u8 addr) { struct stm_miphy_device *dev = miphy->dev; int port = miphy->port; return dev->ops->reg_read(port, addr); } #ifdef DEBUG /* Pretty-ish print of Miphy registers, helpful for debugging */ void stm_miphy_dump_registers(struct stm_miphy *miphy) { printk(KERN_INFO "MIPHY_RESET (0x0): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_RESET)); printk(KERN_INFO "MIPHY_STATUS (0x1): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_STATUS)); printk(KERN_INFO "MIPHY_CONTROL (0x1): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_CONTROL)); printk(KERN_INFO "MIPHY_INT_STATUS (0x4): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_INT_STATUS)); printk(KERN_INFO "MIPHY_BOUNDARY_1 (0x10): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_BOUNDARY_1)); printk(KERN_INFO "MIPHY_BOUNDARY_3 (0x12): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_BOUNDARY_3)); printk(KERN_INFO "MIPHY_COMPENS_CONTROL_1 (0x40): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_COMPENS_CONTROL_1)); printk(KERN_INFO "MIPHY_IDLL_TEST (0x72): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_IDLL_TEST)); printk(KERN_INFO "MIPHY_DES_BITLOCK_CFG (0x85): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_DES_BITLOCK_CFG)); printk(KERN_INFO "MIPHY_DES_BITLOCK (0x86): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_DES_BITLOCK)); printk(KERN_INFO "MIPHY_DES_BITLOCK_STATUS (0x88): 0x%.2x\n", stm_miphy_read(miphy, MIPHY_DES_BITLOCK_STATUS)); } #endif /* DEBUG */ int stm_miphy_sata_status(struct stm_miphy *miphy) { u8 miphy_int_status; struct stm_miphy_device *dev = miphy->dev; mutex_lock(&dev->mutex); miphy_int_status = stm_miphy_read(miphy, 0x4); mutex_unlock(&dev->mutex); return (miphy_int_status & 0x8) || (miphy_int_status & 0x2); } EXPORT_SYMBOL(stm_miphy_sata_status); void stm_miphy_assert_deserializer(struct stm_miphy *miphy, int assert) { struct stm_miphy_device *dev = miphy->dev; mutex_lock(&dev->mutex); stm_miphy_write(miphy, 0x00, assert ? 0x10 : 0x00); mutex_unlock(&dev->mutex); } EXPORT_SYMBOL(stm_miphy_assert_deserializer); int stm_miphy_start(struct stm_miphy *miphy) { struct stm_miphy_device *dev; int port; int rval = -ENODEV; dev = miphy->dev; port = miphy->port; mutex_lock(&dev->mutex); switch (miphy->mode) { case SATA_MODE: switch (dev->type) { case TAP_IF: rval = tap_miphy_sata_start(port, dev); break; case UPORT_IF: rval = mp_miphy_sata_start(port, dev); break; case DUMMY_IF: break; default: BUG(); } break; case PCIE_MODE: switch (dev->type) { case TAP_IF: rval = tap_miphy_pcie_start(port, dev); break; case UPORT_IF: rval = mp_miphy_pcie_start(port, dev); break; case DUMMY_IF: break; default: BUG(); } break; default: BUG(); } /* Clear the contents of interrupt control register, excluding fifooverlap_int */ stm_miphy_write(miphy, MIPHY_INT_STATUS, 0x77); mutex_unlock(&dev->mutex); return rval; } EXPORT_SYMBOL(stm_miphy_start); struct stm_miphy *stm_miphy_claim(int port, enum miphy_mode mode, struct device *owner) { struct stm_miphy *iterator; struct stm_miphy *miphy = NULL; u8 miphy_version, miphy_revision; if (!owner) return NULL; mutex_lock(&miphy_list_mutex); list_for_each_entry(iterator, &miphy_list, node) if (iterator->port == port) { miphy = iterator; break; } if (!miphy) { /* Not found */ pr_warning("MiPhy %d not available\n", port); goto _on_error; } if (miphy->owner) { /* already claimed */ pr_err("MiPhy %d already claimed by %s\n", port, dev_name(miphy->owner)); miphy = NULL; goto _on_error; } if (miphy->mode != mode) { pr_err("MiPHY %d is not in the correct mode\n", port); miphy = NULL; goto _on_error; } miphy->owner = owner; miphy_version = stm_miphy_read(miphy, MIPHY_VERSION); miphy_revision = stm_miphy_read(miphy, MIPHY_REVISION); pr_info("MiPHY%d, c%d.%d Claimed by %s \n", (miphy_version >> 4) & 0x7, (miphy_version & 0xf), miphy_revision, dev_name(miphy->owner)); stm_miphy_start(miphy); _on_error: mutex_unlock(&miphy_list_mutex); return miphy; } EXPORT_SYMBOL(stm_miphy_claim); void stm_miphy_release(struct stm_miphy *miphy) { /* FIXME */ } EXPORT_SYMBOL(stm_miphy_release); void stm_miphy_freeze(struct stm_miphy *miphy) { /* Nothing to do */ } EXPORT_SYMBOL(stm_miphy_freeze); void stm_miphy_thaw(struct stm_miphy *miphy) { stm_miphy_start(miphy); } EXPORT_SYMBOL(stm_miphy_thaw); int miphy_if_register(struct stm_miphy_device *miphy_dev, enum miphy_if_type type, int miphy_first, int miphy_count, enum miphy_mode *modes, struct device *parent, const struct miphy_if_ops *ops) { struct stm_miphy *miphy, *new_miphys; int miphy_num; if (!miphy_class) { miphy_class = class_create(THIS_MODULE, "stm-miphy"); if (IS_ERR(miphy_class)) { printk(KERN_ERR "stm-miphy: can't register class\n"); return PTR_ERR(miphy_class); } } new_miphys = kzalloc(sizeof(*miphy) * miphy_count, GFP_KERNEL); if (!new_miphys) return -ENOMEM; for (miphy_num = miphy_first, miphy = new_miphys; miphy_num < miphy_first + miphy_count; miphy_num++, miphy++) { miphy->dev = miphy_dev; miphy->port = miphy_num; miphy->mode = *modes++; mutex_lock(&miphy_list_mutex); list_add(&miphy->node, &miphy_list); mutex_unlock(&miphy_list_mutex); miphy->device = device_create(miphy_class, parent, 0, miphy, "stm-miphy%d", miphy_num); if (IS_ERR(miphy->device)) return PTR_ERR(miphy->device); } memset(miphy_dev, 0, sizeof(*miphy_dev)); mutex_init(&miphy_dev->mutex); miphy_dev->ops = ops; miphy_dev->type = type; return 0; } int miphy_if_unregister(struct stm_miphy_device *miphy_dev) { /* TODO */ return 0; }