1/* 2 * Copyright (c) 2003-2014 Broadcom Corporation 3 * All Rights Reserved 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the Broadcom 9 * license below: 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 32 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35#include <linux/dma-mapping.h> 36#include <linux/kernel.h> 37#include <linux/delay.h> 38#include <linux/init.h> 39#include <linux/pci.h> 40#include <linux/irq.h> 41#include <linux/bitops.h> 42 43#include <asm/cpu.h> 44#include <asm/mipsregs.h> 45 46#include <asm/netlogic/haldefs.h> 47#include <asm/netlogic/xlp-hal/xlp.h> 48#include <asm/netlogic/common.h> 49#include <asm/netlogic/xlp-hal/iomap.h> 50#include <asm/netlogic/mips-extns.h> 51 52#define SATA_CTL 0x0 53#define SATA_STATUS 0x1 /* Status Reg */ 54#define SATA_INT 0x2 /* Interrupt Reg */ 55#define SATA_INT_MASK 0x3 /* Interrupt Mask Reg */ 56#define SATA_CR_REG_TIMER 0x4 /* PHY Conrol Timer Reg */ 57#define SATA_CORE_ID 0x5 /* Core ID Reg */ 58#define SATA_AXI_SLAVE_OPT1 0x6 /* AXI Slave Options Reg */ 59#define SATA_PHY_LOS_LEV 0x7 /* PHY LOS Level Reg */ 60#define SATA_PHY_MULTI 0x8 /* PHY Multiplier Reg */ 61#define SATA_PHY_CLK_SEL 0x9 /* Clock Select Reg */ 62#define SATA_PHY_AMP1_GEN1 0xa /* PHY Transmit Amplitude Reg 1 */ 63#define SATA_PHY_AMP1_GEN2 0xb /* PHY Transmit Amplitude Reg 2 */ 64#define SATA_PHY_AMP1_GEN3 0xc /* PHY Transmit Amplitude Reg 3 */ 65#define SATA_PHY_PRE1 0xd /* PHY Transmit Preemphasis Reg 1 */ 66#define SATA_PHY_PRE2 0xe /* PHY Transmit Preemphasis Reg 2 */ 67#define SATA_PHY_PRE3 0xf /* PHY Transmit Preemphasis Reg 3 */ 68#define SATA_SPDMODE 0x10 /* Speed Mode Reg */ 69#define SATA_REFCLK 0x11 /* Reference Clock Control Reg */ 70#define SATA_BYTE_SWAP_DIS 0x12 /* byte swap disable */ 71 72/*SATA_CTL Bits */ 73#define SATA_RST_N BIT(0) 74#define PHY0_RESET_N BIT(16) 75#define PHY1_RESET_N BIT(17) 76#define PHY2_RESET_N BIT(18) 77#define PHY3_RESET_N BIT(19) 78#define M_CSYSREQ BIT(2) 79#define S_CSYSREQ BIT(3) 80 81/*SATA_STATUS Bits */ 82#define P0_PHY_READY BIT(4) 83#define P1_PHY_READY BIT(5) 84#define P2_PHY_READY BIT(6) 85#define P3_PHY_READY BIT(7) 86 87#define nlm_read_sata_reg(b, r) nlm_read_reg(b, r) 88#define nlm_write_sata_reg(b, r, v) nlm_write_reg(b, r, v) 89#define nlm_get_sata_pcibase(node) \ 90 nlm_pcicfg_base(XLP_IO_SATA_OFFSET(node)) 91/* SATA device specific configuration registers are starts at 0x900 offset */ 92#define nlm_get_sata_regbase(node) \ 93 (nlm_get_sata_pcibase(node) + 0x900) 94 95static void sata_clear_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) 96{ 97 uint32_t reg_val; 98 99 reg_val = nlm_read_sata_reg(regbase, off); 100 nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); 101} 102 103static void sata_set_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) 104{ 105 uint32_t reg_val; 106 107 reg_val = nlm_read_sata_reg(regbase, off); 108 nlm_write_sata_reg(regbase, off, (reg_val | bit)); 109} 110 111static void nlm_sata_firmware_init(int node) 112{ 113 uint32_t reg_val; 114 uint64_t regbase; 115 int i; 116 117 pr_info("XLP AHCI Initialization started.\n"); 118 regbase = nlm_get_sata_regbase(node); 119 120 /* Reset SATA */ 121 sata_clear_glue_reg(regbase, SATA_CTL, SATA_RST_N); 122 /* Reset PHY */ 123 sata_clear_glue_reg(regbase, SATA_CTL, 124 (PHY3_RESET_N | PHY2_RESET_N 125 | PHY1_RESET_N | PHY0_RESET_N)); 126 127 /* Set SATA */ 128 sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); 129 /* Set PHY */ 130 sata_set_glue_reg(regbase, SATA_CTL, 131 (PHY3_RESET_N | PHY2_RESET_N 132 | PHY1_RESET_N | PHY0_RESET_N)); 133 134 pr_debug("Waiting for PHYs to come up.\n"); 135 i = 0; 136 do { 137 reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); 138 i++; 139 } while (((reg_val & 0xF0) != 0xF0) && (i < 10000)); 140 141 for (i = 0; i < 4; i++) { 142 if (reg_val & (P0_PHY_READY << i)) 143 pr_info("PHY%d is up.\n", i); 144 else 145 pr_info("PHY%d is down.\n", i); 146 } 147 148 pr_info("XLP AHCI init done.\n"); 149} 150 151static int __init nlm_ahci_init(void) 152{ 153 int node = 0; 154 int chip = read_c0_prid() & PRID_IMP_MASK; 155 156 if (chip == PRID_IMP_NETLOGIC_XLP3XX) 157 nlm_sata_firmware_init(node); 158 return 0; 159} 160 161static void nlm_sata_intr_ack(struct irq_data *data) 162{ 163 uint32_t val = 0; 164 uint64_t regbase; 165 166 regbase = nlm_get_sata_regbase(nlm_nodeid()); 167 val = nlm_read_sata_reg(regbase, SATA_INT); 168 sata_set_glue_reg(regbase, SATA_INT, val); 169} 170 171static void nlm_sata_fixup_bar(struct pci_dev *dev) 172{ 173 /* 174 * The AHCI resource is in BAR 0, move it to 175 * BAR 5, where it is expected 176 */ 177 dev->resource[5] = dev->resource[0]; 178 memset(&dev->resource[0], 0, sizeof(dev->resource[0])); 179} 180 181static void nlm_sata_fixup_final(struct pci_dev *dev) 182{ 183 uint32_t val; 184 uint64_t regbase; 185 int node = 0; /* XLP3XX does not support multi-node */ 186 187 regbase = nlm_get_sata_regbase(node); 188 189 /* clear pending interrupts and then enable them */ 190 val = nlm_read_sata_reg(regbase, SATA_INT); 191 sata_set_glue_reg(regbase, SATA_INT, val); 192 193 /* Mask the core interrupt. If all the interrupts 194 * are enabled there are spurious interrupt flow 195 * happening, to avoid only enable core interrupt 196 * mask. 197 */ 198 sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); 199 200 dev->irq = PIC_SATA_IRQ; 201 nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); 202} 203 204arch_initcall(nlm_ahci_init); 205 206DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, 207 nlm_sata_fixup_bar); 208DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, 209 nlm_sata_fixup_final); 210