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