1*aca1545dSVictor Chong /* 2*aca1545dSVictor Chong * Copyright (c) 2016, Linaro Limited 3*aca1545dSVictor Chong * All rights reserved. 4*aca1545dSVictor Chong * 5*aca1545dSVictor Chong * Redistribution and use in source and binary forms, with or without 6*aca1545dSVictor Chong * modification, are permitted provided that the following conditions are met: 7*aca1545dSVictor Chong * 8*aca1545dSVictor Chong * 1. Redistributions of source code must retain the above copyright notice, 9*aca1545dSVictor Chong * this list of conditions and the following disclaimer. 10*aca1545dSVictor Chong * 11*aca1545dSVictor Chong * 2. Redistributions in binary form must reproduce the above copyright notice, 12*aca1545dSVictor Chong * this list of conditions and the following disclaimer in the documentation 13*aca1545dSVictor Chong * and/or other materials provided with the distribution. 14*aca1545dSVictor Chong * 15*aca1545dSVictor Chong * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16*aca1545dSVictor Chong * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*aca1545dSVictor Chong * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*aca1545dSVictor Chong * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19*aca1545dSVictor Chong * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20*aca1545dSVictor Chong * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21*aca1545dSVictor Chong * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22*aca1545dSVictor Chong * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23*aca1545dSVictor Chong * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24*aca1545dSVictor Chong * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25*aca1545dSVictor Chong * POSSIBILITY OF SUCH DAMAGE. 26*aca1545dSVictor Chong * 27*aca1545dSVictor Chong */ 28*aca1545dSVictor Chong 29*aca1545dSVictor Chong #include <assert.h> 30*aca1545dSVictor Chong #include <drivers/pl022_spi.h> 31*aca1545dSVictor Chong #include <gpio.h> 32*aca1545dSVictor Chong #include <initcall.h> 33*aca1545dSVictor Chong #include <io.h> 34*aca1545dSVictor Chong #include <kernel/panic.h> 35*aca1545dSVictor Chong #include <kernel/tee_time.h> 36*aca1545dSVictor Chong #include <platform_config.h> 37*aca1545dSVictor Chong #include <trace.h> 38*aca1545dSVictor Chong #include <util.h> 39*aca1545dSVictor Chong 40*aca1545dSVictor Chong /* SPI register offsets */ 41*aca1545dSVictor Chong #define SSPCR0 0x000 42*aca1545dSVictor Chong #define SSPCR1 0x004 43*aca1545dSVictor Chong #define SSPDR 0x008 44*aca1545dSVictor Chong #define SSPSR 0x00C 45*aca1545dSVictor Chong #define SSPCPSR 0x010 46*aca1545dSVictor Chong #define SSPIMSC 0x014 47*aca1545dSVictor Chong #define SSPRIS 0x018 48*aca1545dSVictor Chong #define SSPMIS 0x01C 49*aca1545dSVictor Chong #define SSPICR 0x020 50*aca1545dSVictor Chong #define SSPDMACR 0x024 51*aca1545dSVictor Chong 52*aca1545dSVictor Chong #ifdef PLATFORM_hikey 53*aca1545dSVictor Chong /* HiKey extensions */ 54*aca1545dSVictor Chong #define SSPTXFIFOCR 0x028 55*aca1545dSVictor Chong #define SSPRXFIFOCR 0x02C 56*aca1545dSVictor Chong #define SSPB2BTRANS 0x030 57*aca1545dSVictor Chong #endif 58*aca1545dSVictor Chong 59*aca1545dSVictor Chong /* test registers */ 60*aca1545dSVictor Chong #define SSPTCR 0x080 61*aca1545dSVictor Chong #define SSPITIP 0x084 62*aca1545dSVictor Chong #define SSPITOP 0x088 63*aca1545dSVictor Chong #define SSPTDR 0x08C 64*aca1545dSVictor Chong 65*aca1545dSVictor Chong #define SSPPeriphID0 0xFE0 66*aca1545dSVictor Chong #define SSPPeriphID1 0xFE4 67*aca1545dSVictor Chong #define SSPPeriphID2 0xFE8 68*aca1545dSVictor Chong #define SSPPeriphID3 0xFEC 69*aca1545dSVictor Chong 70*aca1545dSVictor Chong #define SSPPCellID0 0xFF0 71*aca1545dSVictor Chong #define SSPPCellID1 0xFF4 72*aca1545dSVictor Chong #define SSPPCellID2 0xFF8 73*aca1545dSVictor Chong #define SSPPCellID3 0xFFC 74*aca1545dSVictor Chong 75*aca1545dSVictor Chong /* SPI register masks */ 76*aca1545dSVictor Chong #define SSPCR0_SCR SHIFT_U32(0xFF, 8) 77*aca1545dSVictor Chong #define SSPCR0_SPH SHIFT_U32(1, 7) 78*aca1545dSVictor Chong #define SSPCR0_SPH1 SHIFT_U32(1, 7) 79*aca1545dSVictor Chong #define SSPCR0_SPH0 SHIFT_U32(0, 7) 80*aca1545dSVictor Chong #define SSPCR0_SPO SHIFT_U32(1, 6) 81*aca1545dSVictor Chong #define SSPCR0_SPO1 SHIFT_U32(1, 6) 82*aca1545dSVictor Chong #define SSPCR0_SPO0 SHIFT_U32(0, 6) 83*aca1545dSVictor Chong #define SSPCR0_FRF SHIFT_U32(3, 4) 84*aca1545dSVictor Chong #define SSPCR0_FRF_SPI SHIFT_U32(0, 4) 85*aca1545dSVictor Chong #define SSPCR0_DSS SHIFT_U32(0xFF, 0) 86*aca1545dSVictor Chong #define SSPCR0_DSS_16BIT SHIFT_U32(0xF, 0) 87*aca1545dSVictor Chong #define SSPCR0_DSS_8BIT SHIFT_U32(7, 0) 88*aca1545dSVictor Chong 89*aca1545dSVictor Chong #define SSPCR1_SOD SHIFT_U32(1, 3) 90*aca1545dSVictor Chong #define SSPCR1_SOD_ENABLE SHIFT_U32(1, 3) 91*aca1545dSVictor Chong #define SSPCR1_SOD_DISABLE SHIFT_U32(0, 3) 92*aca1545dSVictor Chong #define SSPCR1_MS SHIFT_U32(1, 2) 93*aca1545dSVictor Chong #define SSPCR1_MS_SLAVE SHIFT_U32(1, 2) 94*aca1545dSVictor Chong #define SSPCR1_MS_MASTER SHIFT_U32(0, 2) 95*aca1545dSVictor Chong #define SSPCR1_SSE SHIFT_U32(1, 1) 96*aca1545dSVictor Chong #define SSPCR1_SSE_ENABLE SHIFT_U32(1, 1) 97*aca1545dSVictor Chong #define SSPCR1_SSE_DISABLE SHIFT_U32(0, 1) 98*aca1545dSVictor Chong #define SSPCR1_LBM SHIFT_U32(1, 0) 99*aca1545dSVictor Chong #define SSPCR1_LBM_YES SHIFT_U32(1, 0) 100*aca1545dSVictor Chong #define SSPCR1_LBM_NO SHIFT_U32(0, 0) 101*aca1545dSVictor Chong 102*aca1545dSVictor Chong #define SSPDR_DATA SHIFT_U32(0xFFFF, 0) 103*aca1545dSVictor Chong 104*aca1545dSVictor Chong #define SSPSR_BSY SHIFT_U32(1, 4) 105*aca1545dSVictor Chong #define SSPSR_RNF SHIFT_U32(1, 3) 106*aca1545dSVictor Chong #define SSPSR_RNE SHIFT_U32(1, 2) 107*aca1545dSVictor Chong #define SSPSR_TNF SHIFT_U32(1, 1) 108*aca1545dSVictor Chong #define SSPSR_TFE SHIFT_U32(1, 0) 109*aca1545dSVictor Chong 110*aca1545dSVictor Chong #define SSPCPSR_CPSDVR SHIFT_U32(0xFF, 0) 111*aca1545dSVictor Chong 112*aca1545dSVictor Chong #define SSPIMSC_TXIM SHIFT_U32(1, 3) 113*aca1545dSVictor Chong #define SSPIMSC_RXIM SHIFT_U32(1, 2) 114*aca1545dSVictor Chong #define SSPIMSC_RTIM SHIFT_U32(1, 1) 115*aca1545dSVictor Chong #define SSPIMSC_RORIM SHIFT_U32(1, 0) 116*aca1545dSVictor Chong 117*aca1545dSVictor Chong #define SSPRIS_TXRIS SHIFT_U32(1, 3) 118*aca1545dSVictor Chong #define SSPRIS_RXRIS SHIFT_U32(1, 2) 119*aca1545dSVictor Chong #define SSPRIS_RTRIS SHIFT_U32(1, 1) 120*aca1545dSVictor Chong #define SSPRIS_RORRIS SHIFT_U32(1, 0) 121*aca1545dSVictor Chong 122*aca1545dSVictor Chong #define SSPMIS_TXMIS SHIFT_U32(1, 3) 123*aca1545dSVictor Chong #define SSPMIS_RXMIS SHIFT_U32(1, 2) 124*aca1545dSVictor Chong #define SSPMIS_RTMIS SHIFT_U32(1, 1) 125*aca1545dSVictor Chong #define SSPMIS_RORMIS SHIFT_U32(1, 0) 126*aca1545dSVictor Chong 127*aca1545dSVictor Chong #define SSPICR_RTIC SHIFT_U32(1, 1) 128*aca1545dSVictor Chong #define SSPICR_RORIC SHIFT_U32(1, 0) 129*aca1545dSVictor Chong 130*aca1545dSVictor Chong #define SSPDMACR_TXDMAE SHIFT_U32(1, 1) 131*aca1545dSVictor Chong #define SSPDMACR_RXDMAE SHIFT_U32(1, 0) 132*aca1545dSVictor Chong 133*aca1545dSVictor Chong #define SSPPeriphID0_PartNumber0 SHIFT_U32(0xFF, 0) /* 0x22 */ 134*aca1545dSVictor Chong #define SSPPeriphID1_Designer0 SHIFT_U32(0xF, 4) /* 0x1 */ 135*aca1545dSVictor Chong #define SSPPeriphID1_PartNumber1 SHIFT_U32(0xF, 0) /* 0x0 */ 136*aca1545dSVictor Chong #define SSPPeriphID2_Revision SHIFT_U32(0xF, 4) 137*aca1545dSVictor Chong #define SSPPeriphID2_Designer1 SHIFT_U32(0xF, 0) /* 0x4 */ 138*aca1545dSVictor Chong #define SSPPeriphID3_Configuration SHIFT_U32(0xFF, 0) /* 0x00 */ 139*aca1545dSVictor Chong 140*aca1545dSVictor Chong #define SSPPCellID_0 SHIFT_U32(0xFF, 0) /* 0x0D */ 141*aca1545dSVictor Chong #define SSPPCellID_1 SHIFT_U32(0xFF, 0) /* 0xF0 */ 142*aca1545dSVictor Chong #define SSPPPCellID_2 SHIFT_U32(0xFF, 0) /* 0x05 */ 143*aca1545dSVictor Chong #define SSPPPCellID_3 SHIFT_U32(0xFF, 0) /* 0xB1 */ 144*aca1545dSVictor Chong 145*aca1545dSVictor Chong #define MASK_32 0xFFFFFFFF 146*aca1545dSVictor Chong #define MASK_28 0xFFFFFFF 147*aca1545dSVictor Chong #define MASK_24 0xFFFFFF 148*aca1545dSVictor Chong #define MASK_20 0xFFFFF 149*aca1545dSVictor Chong #define MASK_16 0xFFFF 150*aca1545dSVictor Chong #define MASK_12 0xFFF 151*aca1545dSVictor Chong #define MASK_8 0xFF 152*aca1545dSVictor Chong #define MASK_4 0xF 153*aca1545dSVictor Chong /* SPI register masks */ 154*aca1545dSVictor Chong 155*aca1545dSVictor Chong #define SSP_CPSDVR_MAX 254 156*aca1545dSVictor Chong #define SSP_CPSDVR_MIN 2 157*aca1545dSVictor Chong #define SSP_SCR_MAX 255 158*aca1545dSVictor Chong #define SSP_SCR_MIN 0 159*aca1545dSVictor Chong #define SSP_DATASIZE_MAX 16 160*aca1545dSVictor Chong 161*aca1545dSVictor Chong enum pl022_data_size { 162*aca1545dSVictor Chong PL022_DATA_SIZE4 = 0x3, 163*aca1545dSVictor Chong PL022_DATA_SIZE5, 164*aca1545dSVictor Chong PL022_DATA_SIZE6, 165*aca1545dSVictor Chong PL022_DATA_SIZE7, 166*aca1545dSVictor Chong PL022_DATA_SIZE8 = SSPCR0_DSS_8BIT, 167*aca1545dSVictor Chong PL022_DATA_SIZE9, 168*aca1545dSVictor Chong PL022_DATA_SIZE10, 169*aca1545dSVictor Chong PL022_DATA_SIZE11, 170*aca1545dSVictor Chong PL022_DATA_SIZE12, 171*aca1545dSVictor Chong PL022_DATA_SIZE13, 172*aca1545dSVictor Chong PL022_DATA_SIZE14, 173*aca1545dSVictor Chong PL022_DATA_SIZE15, 174*aca1545dSVictor Chong PL022_DATA_SIZE16 = SSPCR0_DSS_16BIT 175*aca1545dSVictor Chong }; 176*aca1545dSVictor Chong 177*aca1545dSVictor Chong enum pl022_spi_mode { 178*aca1545dSVictor Chong PL022_SPI_MODE0 = SSPCR0_SPO0 | SSPCR0_SPH0, /* 0x00 */ 179*aca1545dSVictor Chong PL022_SPI_MODE1 = SSPCR0_SPO0 | SSPCR0_SPH1, /* 0x80 */ 180*aca1545dSVictor Chong PL022_SPI_MODE2 = SSPCR0_SPO1 | SSPCR0_SPH0, /* 0x40 */ 181*aca1545dSVictor Chong PL022_SPI_MODE3 = SSPCR0_SPO1 | SSPCR0_SPH1 /* 0xC0 */ 182*aca1545dSVictor Chong }; 183*aca1545dSVictor Chong 184*aca1545dSVictor Chong static void pl022_txrx8(struct spi_chip *chip, uint8_t *wdat, 185*aca1545dSVictor Chong uint8_t *rdat, size_t num_txpkts, size_t *num_rxpkts) 186*aca1545dSVictor Chong { 187*aca1545dSVictor Chong size_t i = 0; 188*aca1545dSVictor Chong size_t j = 0; 189*aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 190*aca1545dSVictor Chong 191*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW); 192*aca1545dSVictor Chong 193*aca1545dSVictor Chong while (i < num_txpkts) { 194*aca1545dSVictor Chong if (read8(pd->base + SSPSR) & SSPSR_TNF) 195*aca1545dSVictor Chong /* tx 1 packet */ 196*aca1545dSVictor Chong write8(wdat[i++], pd->base + SSPDR); 197*aca1545dSVictor Chong } 198*aca1545dSVictor Chong 199*aca1545dSVictor Chong do { 200*aca1545dSVictor Chong while ((read8(pd->base + SSPSR) & SSPSR_RNE) && 201*aca1545dSVictor Chong (j < *num_rxpkts)) 202*aca1545dSVictor Chong /* rx 1 packet */ 203*aca1545dSVictor Chong rdat[j++] = read8(pd->base + SSPDR); 204*aca1545dSVictor Chong } while ((read8(pd->base + SSPSR) & SSPSR_BSY) && (j < *num_rxpkts)); 205*aca1545dSVictor Chong 206*aca1545dSVictor Chong *num_rxpkts = j; 207*aca1545dSVictor Chong 208*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH); 209*aca1545dSVictor Chong } 210*aca1545dSVictor Chong 211*aca1545dSVictor Chong static void pl022_txrx16(struct spi_chip *chip, uint16_t *wdat, 212*aca1545dSVictor Chong uint16_t *rdat, size_t num_txpkts, size_t *num_rxpkts) 213*aca1545dSVictor Chong { 214*aca1545dSVictor Chong size_t i = 0; 215*aca1545dSVictor Chong size_t j = 0; 216*aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 217*aca1545dSVictor Chong 218*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW); 219*aca1545dSVictor Chong 220*aca1545dSVictor Chong while (i < num_txpkts) { 221*aca1545dSVictor Chong if (read8(pd->base + SSPSR) & SSPSR_TNF) 222*aca1545dSVictor Chong /* tx 1 packet */ 223*aca1545dSVictor Chong write16(wdat[i++], pd->base + SSPDR); 224*aca1545dSVictor Chong } 225*aca1545dSVictor Chong 226*aca1545dSVictor Chong do { 227*aca1545dSVictor Chong while ((read8(pd->base + SSPSR) & SSPSR_RNE) 228*aca1545dSVictor Chong && (j < *num_rxpkts)) 229*aca1545dSVictor Chong /* rx 1 packet */ 230*aca1545dSVictor Chong rdat[j++] = read16(pd->base + SSPDR); 231*aca1545dSVictor Chong } while ((read8(pd->base + SSPSR) & SSPSR_BSY) && (j < *num_rxpkts)); 232*aca1545dSVictor Chong 233*aca1545dSVictor Chong *num_rxpkts = j; 234*aca1545dSVictor Chong 235*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH); 236*aca1545dSVictor Chong } 237*aca1545dSVictor Chong 238*aca1545dSVictor Chong static void pl022_tx8(struct spi_chip *chip, uint8_t *wdat, 239*aca1545dSVictor Chong size_t num_txpkts) 240*aca1545dSVictor Chong { 241*aca1545dSVictor Chong size_t i = 0; 242*aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 243*aca1545dSVictor Chong 244*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW); 245*aca1545dSVictor Chong 246*aca1545dSVictor Chong while (i < num_txpkts) { 247*aca1545dSVictor Chong if (read8(pd->base + SSPSR) & SSPSR_TNF) 248*aca1545dSVictor Chong /* tx 1 packet */ 249*aca1545dSVictor Chong write8(wdat[i++], pd->base + SSPDR); 250*aca1545dSVictor Chong } 251*aca1545dSVictor Chong 252*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH); 253*aca1545dSVictor Chong } 254*aca1545dSVictor Chong 255*aca1545dSVictor Chong static void pl022_tx16(struct spi_chip *chip, uint16_t *wdat, 256*aca1545dSVictor Chong size_t num_txpkts) 257*aca1545dSVictor Chong { 258*aca1545dSVictor Chong size_t i = 0; 259*aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 260*aca1545dSVictor Chong 261*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW); 262*aca1545dSVictor Chong 263*aca1545dSVictor Chong while (i < num_txpkts) { 264*aca1545dSVictor Chong if (read8(pd->base + SSPSR) & SSPSR_TNF) 265*aca1545dSVictor Chong /* tx 1 packet */ 266*aca1545dSVictor Chong write16(wdat[i++], pd->base + SSPDR); 267*aca1545dSVictor Chong } 268*aca1545dSVictor Chong 269*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH); 270*aca1545dSVictor Chong } 271*aca1545dSVictor Chong 272*aca1545dSVictor Chong static void pl022_rx8(struct spi_chip *chip, uint8_t *rdat, 273*aca1545dSVictor Chong size_t *num_rxpkts) 274*aca1545dSVictor Chong { 275*aca1545dSVictor Chong size_t j = 0; 276*aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 277*aca1545dSVictor Chong 278*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW); 279*aca1545dSVictor Chong 280*aca1545dSVictor Chong do { 281*aca1545dSVictor Chong while ((read8(pd->base + SSPSR) & SSPSR_RNE) && 282*aca1545dSVictor Chong (j < *num_rxpkts)) 283*aca1545dSVictor Chong /* rx 1 packet */ 284*aca1545dSVictor Chong rdat[j++] = read8(pd->base + SSPDR); 285*aca1545dSVictor Chong } while ((read8(pd->base + SSPSR) & SSPSR_BSY) && (j < *num_rxpkts)); 286*aca1545dSVictor Chong 287*aca1545dSVictor Chong *num_rxpkts = j; 288*aca1545dSVictor Chong 289*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH); 290*aca1545dSVictor Chong } 291*aca1545dSVictor Chong 292*aca1545dSVictor Chong static void pl022_rx16(struct spi_chip *chip, uint16_t *rdat, 293*aca1545dSVictor Chong size_t *num_rxpkts) 294*aca1545dSVictor Chong { 295*aca1545dSVictor Chong size_t j = 0; 296*aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 297*aca1545dSVictor Chong 298*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW); 299*aca1545dSVictor Chong 300*aca1545dSVictor Chong do { 301*aca1545dSVictor Chong while ((read8(pd->base + SSPSR) & SSPSR_RNE) && 302*aca1545dSVictor Chong (j < *num_rxpkts)) 303*aca1545dSVictor Chong /* rx 1 packet */ 304*aca1545dSVictor Chong rdat[j++] = read16(pd->base + SSPDR); 305*aca1545dSVictor Chong } while ((read8(pd->base + SSPSR) & SSPSR_BSY) && (j < *num_rxpkts)); 306*aca1545dSVictor Chong 307*aca1545dSVictor Chong *num_rxpkts = j; 308*aca1545dSVictor Chong 309*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH); 310*aca1545dSVictor Chong } 311*aca1545dSVictor Chong 312*aca1545dSVictor Chong static void pl022_print_peri_id(struct pl022_data *pd __maybe_unused) 313*aca1545dSVictor Chong { 314*aca1545dSVictor Chong DMSG("Expected: 0x 22 10 ?4 00"); 315*aca1545dSVictor Chong DMSG("Read: 0x %02x %02x %02x %02x", 316*aca1545dSVictor Chong read32(pd->base + SSPPeriphID0), 317*aca1545dSVictor Chong read32(pd->base + SSPPeriphID1), 318*aca1545dSVictor Chong read32(pd->base + SSPPeriphID2), 319*aca1545dSVictor Chong read32(pd->base + SSPPeriphID3)); 320*aca1545dSVictor Chong } 321*aca1545dSVictor Chong 322*aca1545dSVictor Chong static void pl022_print_cell_id(struct pl022_data *pd __maybe_unused) 323*aca1545dSVictor Chong { 324*aca1545dSVictor Chong DMSG("Expected: 0x 0d f0 05 b1"); 325*aca1545dSVictor Chong DMSG("Read: 0x %02x %02x %02x %02x", 326*aca1545dSVictor Chong read32(pd->base + SSPPCellID0), 327*aca1545dSVictor Chong read32(pd->base + SSPPCellID1), 328*aca1545dSVictor Chong read32(pd->base + SSPPCellID2), 329*aca1545dSVictor Chong read32(pd->base + SSPPCellID3)); 330*aca1545dSVictor Chong } 331*aca1545dSVictor Chong 332*aca1545dSVictor Chong static void pl022_sanity_check(struct pl022_data *pd) 333*aca1545dSVictor Chong { 334*aca1545dSVictor Chong assert(pd); 335*aca1545dSVictor Chong assert(pd->chip.ops); 336*aca1545dSVictor Chong assert(pd->base); 337*aca1545dSVictor Chong assert(pd->cs_gpio_base); 338*aca1545dSVictor Chong assert(pd->clk_hz); 339*aca1545dSVictor Chong assert(pd->speed_hz && pd->speed_hz <= pd->clk_hz/2); 340*aca1545dSVictor Chong assert(pd->mode <= SPI_MODE3); 341*aca1545dSVictor Chong assert(pd->data_size_bits == 8 || pd->data_size_bits == 16); 342*aca1545dSVictor Chong 343*aca1545dSVictor Chong #ifdef PLATFORM_hikey 344*aca1545dSVictor Chong DMSG("SSPB2BTRANS: Expected: 0x2. Read: 0x%x", 345*aca1545dSVictor Chong read32(pd->base + SSPB2BTRANS)); 346*aca1545dSVictor Chong #endif 347*aca1545dSVictor Chong pl022_print_peri_id(pd); 348*aca1545dSVictor Chong pl022_print_cell_id(pd); 349*aca1545dSVictor Chong } 350*aca1545dSVictor Chong 351*aca1545dSVictor Chong static inline uint32_t pl022_calc_freq(struct pl022_data *pd, 352*aca1545dSVictor Chong uint8_t cpsdvr, uint8_t scr) 353*aca1545dSVictor Chong { 354*aca1545dSVictor Chong return pd->clk_hz / (cpsdvr * (1 + scr)); 355*aca1545dSVictor Chong } 356*aca1545dSVictor Chong 357*aca1545dSVictor Chong static void pl022_calc_clk_divisors(struct pl022_data *pd, 358*aca1545dSVictor Chong uint8_t *cpsdvr, uint8_t *scr) 359*aca1545dSVictor Chong { 360*aca1545dSVictor Chong unsigned int freq1 = 0; 361*aca1545dSVictor Chong unsigned int freq2 = 0; 362*aca1545dSVictor Chong uint8_t tmp_cpsdvr1; 363*aca1545dSVictor Chong uint8_t tmp_scr1; 364*aca1545dSVictor Chong uint8_t tmp_cpsdvr2 = 0; 365*aca1545dSVictor Chong uint8_t tmp_scr2 = 0; 366*aca1545dSVictor Chong 367*aca1545dSVictor Chong for (tmp_scr1 = SSP_SCR_MIN; tmp_scr1 < SSP_SCR_MAX; tmp_scr1++) { 368*aca1545dSVictor Chong for (tmp_cpsdvr1 = SSP_CPSDVR_MIN; tmp_cpsdvr1 < SSP_CPSDVR_MAX; 369*aca1545dSVictor Chong tmp_cpsdvr1++) { 370*aca1545dSVictor Chong freq1 = pl022_calc_freq(pd, tmp_cpsdvr1, tmp_scr1); 371*aca1545dSVictor Chong if (freq1 == pd->speed_hz) 372*aca1545dSVictor Chong goto done; 373*aca1545dSVictor Chong else if (freq1 < pd->speed_hz) 374*aca1545dSVictor Chong goto stage2; 375*aca1545dSVictor Chong } 376*aca1545dSVictor Chong } 377*aca1545dSVictor Chong 378*aca1545dSVictor Chong stage2: 379*aca1545dSVictor Chong for (tmp_cpsdvr2 = SSP_CPSDVR_MIN; tmp_cpsdvr2 < SSP_CPSDVR_MAX; 380*aca1545dSVictor Chong tmp_cpsdvr2++) { 381*aca1545dSVictor Chong for (tmp_scr2 = SSP_SCR_MIN; tmp_scr2 < SSP_SCR_MAX; 382*aca1545dSVictor Chong tmp_scr2++) { 383*aca1545dSVictor Chong freq2 = pl022_calc_freq(pd, tmp_cpsdvr2, tmp_scr2); 384*aca1545dSVictor Chong if (freq2 <= pd->speed_hz) 385*aca1545dSVictor Chong goto done; 386*aca1545dSVictor Chong } 387*aca1545dSVictor Chong } 388*aca1545dSVictor Chong 389*aca1545dSVictor Chong done: 390*aca1545dSVictor Chong if (freq1 >= freq2) { 391*aca1545dSVictor Chong *cpsdvr = tmp_cpsdvr1; 392*aca1545dSVictor Chong *scr = tmp_scr1; 393*aca1545dSVictor Chong DMSG("speed: requested: %u, closest1: %u", 394*aca1545dSVictor Chong pd->speed_hz, freq1); 395*aca1545dSVictor Chong } else { 396*aca1545dSVictor Chong *cpsdvr = tmp_cpsdvr2; 397*aca1545dSVictor Chong *scr = tmp_scr2; 398*aca1545dSVictor Chong DMSG("speed: requested: %u, closest2: %u", 399*aca1545dSVictor Chong pd->speed_hz, freq2); 400*aca1545dSVictor Chong } 401*aca1545dSVictor Chong DMSG("CPSDVR: %u (0x%x), SCR: %u (0x%x)", 402*aca1545dSVictor Chong *cpsdvr, *cpsdvr, *scr, *scr); 403*aca1545dSVictor Chong } 404*aca1545dSVictor Chong 405*aca1545dSVictor Chong static void pl022_flush_fifo(struct pl022_data *pd) 406*aca1545dSVictor Chong { 407*aca1545dSVictor Chong uint32_t __maybe_unused rdat; 408*aca1545dSVictor Chong 409*aca1545dSVictor Chong do { 410*aca1545dSVictor Chong while (read32(pd->base + SSPSR) & SSPSR_RNE) { 411*aca1545dSVictor Chong rdat = read32(pd->base + SSPDR); 412*aca1545dSVictor Chong DMSG("rdat: 0x%x", rdat); 413*aca1545dSVictor Chong } 414*aca1545dSVictor Chong } while (read32(pd->base + SSPSR) & SSPSR_BSY); 415*aca1545dSVictor Chong } 416*aca1545dSVictor Chong 417*aca1545dSVictor Chong static const struct spi_ops pl022_ops = { 418*aca1545dSVictor Chong .txrx8 = pl022_txrx8, 419*aca1545dSVictor Chong .txrx16 = pl022_txrx16, 420*aca1545dSVictor Chong .tx8 = pl022_tx8, 421*aca1545dSVictor Chong .tx16 = pl022_tx16, 422*aca1545dSVictor Chong .rx8 = pl022_rx8, 423*aca1545dSVictor Chong .rx16 = pl022_rx16, 424*aca1545dSVictor Chong }; 425*aca1545dSVictor Chong 426*aca1545dSVictor Chong void pl022_configure(struct pl022_data *pd) 427*aca1545dSVictor Chong { 428*aca1545dSVictor Chong uint16_t mode; 429*aca1545dSVictor Chong uint16_t data_size; 430*aca1545dSVictor Chong uint8_t cpsdvr; 431*aca1545dSVictor Chong uint8_t scr; 432*aca1545dSVictor Chong uint8_t lbm; 433*aca1545dSVictor Chong 434*aca1545dSVictor Chong pd->chip.ops = &pl022_ops; 435*aca1545dSVictor Chong pl022_sanity_check(pd); 436*aca1545dSVictor Chong pl022_calc_clk_divisors(pd, &cpsdvr, &scr); 437*aca1545dSVictor Chong 438*aca1545dSVictor Chong /* configure ssp based on platform settings */ 439*aca1545dSVictor Chong switch (pd->mode) { 440*aca1545dSVictor Chong case SPI_MODE0: 441*aca1545dSVictor Chong DMSG("SPI_MODE0"); 442*aca1545dSVictor Chong mode = PL022_SPI_MODE0; 443*aca1545dSVictor Chong break; 444*aca1545dSVictor Chong case SPI_MODE1: 445*aca1545dSVictor Chong DMSG("SPI_MODE1"); 446*aca1545dSVictor Chong mode = PL022_SPI_MODE1; 447*aca1545dSVictor Chong break; 448*aca1545dSVictor Chong case SPI_MODE2: 449*aca1545dSVictor Chong DMSG("SPI_MODE2"); 450*aca1545dSVictor Chong mode = PL022_SPI_MODE2; 451*aca1545dSVictor Chong break; 452*aca1545dSVictor Chong case SPI_MODE3: 453*aca1545dSVictor Chong DMSG("SPI_MODE3"); 454*aca1545dSVictor Chong mode = PL022_SPI_MODE3; 455*aca1545dSVictor Chong break; 456*aca1545dSVictor Chong default: 457*aca1545dSVictor Chong EMSG("Invalid SPI mode: %u", pd->mode); 458*aca1545dSVictor Chong panic(); 459*aca1545dSVictor Chong } 460*aca1545dSVictor Chong 461*aca1545dSVictor Chong switch (pd->data_size_bits) { 462*aca1545dSVictor Chong case 8: 463*aca1545dSVictor Chong DMSG("Data size: 8"); 464*aca1545dSVictor Chong data_size = PL022_DATA_SIZE8; 465*aca1545dSVictor Chong break; 466*aca1545dSVictor Chong case 16: 467*aca1545dSVictor Chong DMSG("Data size: 16"); 468*aca1545dSVictor Chong data_size = PL022_DATA_SIZE16; 469*aca1545dSVictor Chong break; 470*aca1545dSVictor Chong default: 471*aca1545dSVictor Chong EMSG("Unsupported data size: %u bits", pd->data_size_bits); 472*aca1545dSVictor Chong panic(); 473*aca1545dSVictor Chong } 474*aca1545dSVictor Chong 475*aca1545dSVictor Chong if (pd->loopback) { 476*aca1545dSVictor Chong DMSG("Starting in loopback mode!"); 477*aca1545dSVictor Chong lbm = SSPCR1_LBM_YES; 478*aca1545dSVictor Chong } else { 479*aca1545dSVictor Chong DMSG("Starting in regular (non-loopback) mode!"); 480*aca1545dSVictor Chong lbm = SSPCR1_LBM_NO; 481*aca1545dSVictor Chong } 482*aca1545dSVictor Chong 483*aca1545dSVictor Chong DMSG("set Serial Clock Rate (SCR), SPI mode (phase and clock)"); 484*aca1545dSVictor Chong DMSG("set frame format (SPI) and data size (8- or 16-bit)"); 485*aca1545dSVictor Chong io_mask16(pd->base + SSPCR0, SHIFT_U32(scr, 8) | mode | SSPCR0_FRF_SPI | 486*aca1545dSVictor Chong data_size, MASK_16); 487*aca1545dSVictor Chong 488*aca1545dSVictor Chong DMSG("set master mode, disable SSP, set loopback mode"); 489*aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SOD_DISABLE | SSPCR1_MS_MASTER | 490*aca1545dSVictor Chong SSPCR1_SSE_DISABLE | lbm, MASK_4); 491*aca1545dSVictor Chong 492*aca1545dSVictor Chong DMSG("set clock prescale"); 493*aca1545dSVictor Chong io_mask8(pd->base + SSPCPSR, cpsdvr, SSPCPSR_CPSDVR); 494*aca1545dSVictor Chong 495*aca1545dSVictor Chong DMSG("disable interrupts"); 496*aca1545dSVictor Chong io_mask8(pd->base + SSPIMSC, 0, MASK_4); 497*aca1545dSVictor Chong 498*aca1545dSVictor Chong DMSG("set CS GPIO dir to out"); 499*aca1545dSVictor Chong gpio_set_direction(pd->cs_gpio_pin, GPIO_DIR_OUT); 500*aca1545dSVictor Chong 501*aca1545dSVictor Chong DMSG("pull CS high"); 502*aca1545dSVictor Chong gpio_set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH); 503*aca1545dSVictor Chong } 504*aca1545dSVictor Chong 505*aca1545dSVictor Chong void pl022_start(struct pl022_data *pd) 506*aca1545dSVictor Chong { 507*aca1545dSVictor Chong DMSG("empty FIFO before starting"); 508*aca1545dSVictor Chong pl022_flush_fifo(pd); 509*aca1545dSVictor Chong 510*aca1545dSVictor Chong DMSG("enable SSP"); 511*aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SSE_ENABLE, SSPCR1_SSE); 512*aca1545dSVictor Chong } 513*aca1545dSVictor Chong 514*aca1545dSVictor Chong void pl022_end(struct pl022_data *pd) 515*aca1545dSVictor Chong { 516*aca1545dSVictor Chong /* disable ssp */ 517*aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SSE_DISABLE, SSPCR1_SSE); 518*aca1545dSVictor Chong } 519*aca1545dSVictor Chong 520