Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: Netlogic: Support for XLP3XX on-chip SATA

XLP3XX includes an on-chip SATA controller with 4 ports. The
controller needs glue logic initialization and PCI fixup before
it can be used with the standard AHCI driver.

Signed-off-by: Ganesan Ramalingam <ganesanr@broadcom.com>
Signed-off-by: Jayachandran C <jchandra@broadcom.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/6872/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Ganesan Ramalingam and committed by
Ralf Baechle
a9514409 d66f3f0e

+210
+1
arch/mips/netlogic/xlp/Makefile
··· 2 2 obj-$(CONFIG_SMP) += wakeup.o 3 3 obj-$(CONFIG_USB) += usb-init.o 4 4 obj-$(CONFIG_USB) += usb-init-xlp2.o 5 + obj-$(CONFIG_SATA_AHCI) += ahci-init.o
+209
arch/mips/netlogic/xlp/ahci-init.c
··· 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 + 95 + static 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 + 103 + static 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 + 111 + static 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 + 151 + static int __init nlm_ahci_init(void) 152 + { 153 + int node = 0; 154 + int chip = read_c0_prid() & PRID_REV_MASK; 155 + 156 + if (chip == PRID_IMP_NETLOGIC_XLP3XX) 157 + nlm_sata_firmware_init(node); 158 + return 0; 159 + } 160 + 161 + static 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 + 171 + static 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 + 181 + static 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 + 204 + arch_initcall(nlm_ahci_init); 205 + 206 + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, 207 + nlm_sata_fixup_bar); 208 + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, 209 + nlm_sata_fixup_final);