11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2aca1545dSVictor Chong /* 3aca1545dSVictor Chong * Copyright (c) 2016, Linaro Limited 4aca1545dSVictor Chong * 5aca1545dSVictor Chong */ 6aca1545dSVictor Chong 7aca1545dSVictor Chong #include <assert.h> 8aca1545dSVictor Chong #include <drivers/pl022_spi.h> 9aca1545dSVictor Chong #include <initcall.h> 10aca1545dSVictor Chong #include <io.h> 11aca1545dSVictor Chong #include <kernel/panic.h> 12aca1545dSVictor Chong #include <kernel/tee_time.h> 13aca1545dSVictor Chong #include <platform_config.h> 14aca1545dSVictor Chong #include <trace.h> 15aca1545dSVictor Chong #include <util.h> 16aca1545dSVictor Chong 17aca1545dSVictor Chong /* SPI register offsets */ 18aca1545dSVictor Chong #define SSPCR0 0x000 19aca1545dSVictor Chong #define SSPCR1 0x004 20aca1545dSVictor Chong #define SSPDR 0x008 21aca1545dSVictor Chong #define SSPSR 0x00C 22aca1545dSVictor Chong #define SSPCPSR 0x010 23aca1545dSVictor Chong #define SSPIMSC 0x014 24aca1545dSVictor Chong #define SSPRIS 0x018 25aca1545dSVictor Chong #define SSPMIS 0x01C 26aca1545dSVictor Chong #define SSPICR 0x020 27aca1545dSVictor Chong #define SSPDMACR 0x024 28aca1545dSVictor Chong 29aca1545dSVictor Chong #ifdef PLATFORM_hikey 30aca1545dSVictor Chong /* HiKey extensions */ 31aca1545dSVictor Chong #define SSPTXFIFOCR 0x028 32aca1545dSVictor Chong #define SSPRXFIFOCR 0x02C 33aca1545dSVictor Chong #define SSPB2BTRANS 0x030 34aca1545dSVictor Chong #endif 35aca1545dSVictor Chong 36aca1545dSVictor Chong /* test registers */ 37aca1545dSVictor Chong #define SSPTCR 0x080 38aca1545dSVictor Chong #define SSPITIP 0x084 39aca1545dSVictor Chong #define SSPITOP 0x088 40aca1545dSVictor Chong #define SSPTDR 0x08C 41aca1545dSVictor Chong 42aca1545dSVictor Chong #define SSPPeriphID0 0xFE0 43aca1545dSVictor Chong #define SSPPeriphID1 0xFE4 44aca1545dSVictor Chong #define SSPPeriphID2 0xFE8 45aca1545dSVictor Chong #define SSPPeriphID3 0xFEC 46aca1545dSVictor Chong 47aca1545dSVictor Chong #define SSPPCellID0 0xFF0 48aca1545dSVictor Chong #define SSPPCellID1 0xFF4 49aca1545dSVictor Chong #define SSPPCellID2 0xFF8 50aca1545dSVictor Chong #define SSPPCellID3 0xFFC 51aca1545dSVictor Chong 52aca1545dSVictor Chong /* SPI register masks */ 53aca1545dSVictor Chong #define SSPCR0_SCR SHIFT_U32(0xFF, 8) 54aca1545dSVictor Chong #define SSPCR0_SPH SHIFT_U32(1, 7) 55aca1545dSVictor Chong #define SSPCR0_SPH1 SHIFT_U32(1, 7) 56aca1545dSVictor Chong #define SSPCR0_SPH0 SHIFT_U32(0, 7) 57aca1545dSVictor Chong #define SSPCR0_SPO SHIFT_U32(1, 6) 58aca1545dSVictor Chong #define SSPCR0_SPO1 SHIFT_U32(1, 6) 59aca1545dSVictor Chong #define SSPCR0_SPO0 SHIFT_U32(0, 6) 60aca1545dSVictor Chong #define SSPCR0_FRF SHIFT_U32(3, 4) 61aca1545dSVictor Chong #define SSPCR0_FRF_SPI SHIFT_U32(0, 4) 62aca1545dSVictor Chong #define SSPCR0_DSS SHIFT_U32(0xFF, 0) 63aca1545dSVictor Chong #define SSPCR0_DSS_16BIT SHIFT_U32(0xF, 0) 64aca1545dSVictor Chong #define SSPCR0_DSS_8BIT SHIFT_U32(7, 0) 65aca1545dSVictor Chong 66aca1545dSVictor Chong #define SSPCR1_SOD SHIFT_U32(1, 3) 67aca1545dSVictor Chong #define SSPCR1_SOD_ENABLE SHIFT_U32(1, 3) 68aca1545dSVictor Chong #define SSPCR1_SOD_DISABLE SHIFT_U32(0, 3) 69aca1545dSVictor Chong #define SSPCR1_MS SHIFT_U32(1, 2) 70aca1545dSVictor Chong #define SSPCR1_MS_SLAVE SHIFT_U32(1, 2) 71aca1545dSVictor Chong #define SSPCR1_MS_MASTER SHIFT_U32(0, 2) 72aca1545dSVictor Chong #define SSPCR1_SSE SHIFT_U32(1, 1) 73aca1545dSVictor Chong #define SSPCR1_SSE_ENABLE SHIFT_U32(1, 1) 74aca1545dSVictor Chong #define SSPCR1_SSE_DISABLE SHIFT_U32(0, 1) 75aca1545dSVictor Chong #define SSPCR1_LBM SHIFT_U32(1, 0) 76aca1545dSVictor Chong #define SSPCR1_LBM_YES SHIFT_U32(1, 0) 77aca1545dSVictor Chong #define SSPCR1_LBM_NO SHIFT_U32(0, 0) 78aca1545dSVictor Chong 79aca1545dSVictor Chong #define SSPDR_DATA SHIFT_U32(0xFFFF, 0) 80aca1545dSVictor Chong 81aca1545dSVictor Chong #define SSPSR_BSY SHIFT_U32(1, 4) 82aca1545dSVictor Chong #define SSPSR_RNF SHIFT_U32(1, 3) 83aca1545dSVictor Chong #define SSPSR_RNE SHIFT_U32(1, 2) 84aca1545dSVictor Chong #define SSPSR_TNF SHIFT_U32(1, 1) 85aca1545dSVictor Chong #define SSPSR_TFE SHIFT_U32(1, 0) 86aca1545dSVictor Chong 87aca1545dSVictor Chong #define SSPCPSR_CPSDVR SHIFT_U32(0xFF, 0) 88aca1545dSVictor Chong 89aca1545dSVictor Chong #define SSPIMSC_TXIM SHIFT_U32(1, 3) 90aca1545dSVictor Chong #define SSPIMSC_RXIM SHIFT_U32(1, 2) 91aca1545dSVictor Chong #define SSPIMSC_RTIM SHIFT_U32(1, 1) 92aca1545dSVictor Chong #define SSPIMSC_RORIM SHIFT_U32(1, 0) 93aca1545dSVictor Chong 94aca1545dSVictor Chong #define SSPRIS_TXRIS SHIFT_U32(1, 3) 95aca1545dSVictor Chong #define SSPRIS_RXRIS SHIFT_U32(1, 2) 96aca1545dSVictor Chong #define SSPRIS_RTRIS SHIFT_U32(1, 1) 97aca1545dSVictor Chong #define SSPRIS_RORRIS SHIFT_U32(1, 0) 98aca1545dSVictor Chong 99aca1545dSVictor Chong #define SSPMIS_TXMIS SHIFT_U32(1, 3) 100aca1545dSVictor Chong #define SSPMIS_RXMIS SHIFT_U32(1, 2) 101aca1545dSVictor Chong #define SSPMIS_RTMIS SHIFT_U32(1, 1) 102aca1545dSVictor Chong #define SSPMIS_RORMIS SHIFT_U32(1, 0) 103aca1545dSVictor Chong 104aca1545dSVictor Chong #define SSPICR_RTIC SHIFT_U32(1, 1) 105aca1545dSVictor Chong #define SSPICR_RORIC SHIFT_U32(1, 0) 106aca1545dSVictor Chong 107aca1545dSVictor Chong #define SSPDMACR_TXDMAE SHIFT_U32(1, 1) 108aca1545dSVictor Chong #define SSPDMACR_RXDMAE SHIFT_U32(1, 0) 109aca1545dSVictor Chong 110aca1545dSVictor Chong #define SSPPeriphID0_PartNumber0 SHIFT_U32(0xFF, 0) /* 0x22 */ 111aca1545dSVictor Chong #define SSPPeriphID1_Designer0 SHIFT_U32(0xF, 4) /* 0x1 */ 112aca1545dSVictor Chong #define SSPPeriphID1_PartNumber1 SHIFT_U32(0xF, 0) /* 0x0 */ 113aca1545dSVictor Chong #define SSPPeriphID2_Revision SHIFT_U32(0xF, 4) 114aca1545dSVictor Chong #define SSPPeriphID2_Designer1 SHIFT_U32(0xF, 0) /* 0x4 */ 115aca1545dSVictor Chong #define SSPPeriphID3_Configuration SHIFT_U32(0xFF, 0) /* 0x00 */ 116aca1545dSVictor Chong 117aca1545dSVictor Chong #define SSPPCellID_0 SHIFT_U32(0xFF, 0) /* 0x0D */ 118aca1545dSVictor Chong #define SSPPCellID_1 SHIFT_U32(0xFF, 0) /* 0xF0 */ 119aca1545dSVictor Chong #define SSPPPCellID_2 SHIFT_U32(0xFF, 0) /* 0x05 */ 120aca1545dSVictor Chong #define SSPPPCellID_3 SHIFT_U32(0xFF, 0) /* 0xB1 */ 121aca1545dSVictor Chong 122aca1545dSVictor Chong #define MASK_32 0xFFFFFFFF 123aca1545dSVictor Chong #define MASK_28 0xFFFFFFF 124aca1545dSVictor Chong #define MASK_24 0xFFFFFF 125aca1545dSVictor Chong #define MASK_20 0xFFFFF 126aca1545dSVictor Chong #define MASK_16 0xFFFF 127aca1545dSVictor Chong #define MASK_12 0xFFF 128aca1545dSVictor Chong #define MASK_8 0xFF 129aca1545dSVictor Chong #define MASK_4 0xF 130aca1545dSVictor Chong /* SPI register masks */ 131aca1545dSVictor Chong 132aca1545dSVictor Chong #define SSP_CPSDVR_MAX 254 133aca1545dSVictor Chong #define SSP_CPSDVR_MIN 2 134aca1545dSVictor Chong #define SSP_SCR_MAX 255 135aca1545dSVictor Chong #define SSP_SCR_MIN 0 136aca1545dSVictor Chong #define SSP_DATASIZE_MAX 16 137aca1545dSVictor Chong 1389a2efe04SVictor Chong static enum spi_result pl022_txrx8(struct spi_chip *chip, uint8_t *wdat, 1399a2efe04SVictor Chong uint8_t *rdat, size_t num_pkts) 140aca1545dSVictor Chong { 141aca1545dSVictor Chong size_t i = 0; 142aca1545dSVictor Chong size_t j = 0; 143aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 144aca1545dSVictor Chong 1459a2efe04SVictor Chong 1469a2efe04SVictor Chong if (pd->data_size_bits != 8) { 1479a2efe04SVictor Chong EMSG("data_size_bits should be 8, not %u", 1489a2efe04SVictor Chong pd->data_size_bits); 1499a2efe04SVictor Chong return SPI_ERR_CFG; 1509a2efe04SVictor Chong } 1519a2efe04SVictor Chong 1522ff86f60SVictor Chong if (wdat) 15372057c7cSVictor Chong while (i < num_pkts) { 154*918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_TNF) { 155aca1545dSVictor Chong /* tx 1 packet */ 156*918bb3a5SEtienne Carriere io_write8(pd->base + SSPDR, wdat[i++]); 157aca1545dSVictor Chong } 158aca1545dSVictor Chong 15972057c7cSVictor Chong if (rdat) 160*918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_RNE) { 16172057c7cSVictor Chong /* rx 1 packet */ 162*918bb3a5SEtienne Carriere rdat[j++] = io_read8(pd->base + SSPDR); 16372057c7cSVictor Chong } 16472057c7cSVictor Chong } 16572057c7cSVictor Chong 16672057c7cSVictor Chong /* Capture remaining rdat not read above */ 1679a2efe04SVictor Chong if (rdat) { 1689a2efe04SVictor Chong while ((j < num_pkts) && 169*918bb3a5SEtienne Carriere (io_read8(pd->base + SSPSR) & SSPSR_BSY)) 170*918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_RNE) { 171aca1545dSVictor Chong /* rx 1 packet */ 172*918bb3a5SEtienne Carriere rdat[j++] = io_read8(pd->base + SSPDR); 1732ff86f60SVictor Chong } 174aca1545dSVictor Chong 1759a2efe04SVictor Chong if (j < num_pkts) { 1769a2efe04SVictor Chong EMSG("Packets requested %zu, received %zu", 1779a2efe04SVictor Chong num_pkts, j); 1789a2efe04SVictor Chong return SPI_ERR_PKTCNT; 1799a2efe04SVictor Chong } 180aca1545dSVictor Chong } 181aca1545dSVictor Chong 1829a2efe04SVictor Chong return SPI_OK; 1839a2efe04SVictor Chong } 1849a2efe04SVictor Chong 1859a2efe04SVictor Chong static enum spi_result pl022_txrx16(struct spi_chip *chip, uint16_t *wdat, 1869a2efe04SVictor Chong uint16_t *rdat, size_t num_pkts) 187aca1545dSVictor Chong { 188aca1545dSVictor Chong size_t i = 0; 189aca1545dSVictor Chong size_t j = 0; 190aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 191aca1545dSVictor Chong 1929a2efe04SVictor Chong if (pd->data_size_bits != 16) { 1939a2efe04SVictor Chong EMSG("data_size_bits should be 16, not %u", 1949a2efe04SVictor Chong pd->data_size_bits); 1959a2efe04SVictor Chong return SPI_ERR_CFG; 1969a2efe04SVictor Chong } 1979a2efe04SVictor Chong 1982ff86f60SVictor Chong if (wdat) 19972057c7cSVictor Chong while (i < num_pkts) { 200*918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_TNF) { 201aca1545dSVictor Chong /* tx 1 packet */ 202*918bb3a5SEtienne Carriere io_write16(pd->base + SSPDR, wdat[i++]); 203aca1545dSVictor Chong } 204aca1545dSVictor Chong 20572057c7cSVictor Chong if (rdat) 206*918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_RNE) { 20772057c7cSVictor Chong /* rx 1 packet */ 208*918bb3a5SEtienne Carriere rdat[j++] = io_read8(pd->base + SSPDR); 20972057c7cSVictor Chong } 21072057c7cSVictor Chong } 21172057c7cSVictor Chong 21272057c7cSVictor Chong /* Capture remaining rdat not read above */ 2139a2efe04SVictor Chong if (rdat) { 2149a2efe04SVictor Chong while ((j < num_pkts) && 215*918bb3a5SEtienne Carriere (io_read8(pd->base + SSPSR) & SSPSR_BSY)) 216*918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_RNE) { 217aca1545dSVictor Chong /* rx 1 packet */ 218*918bb3a5SEtienne Carriere rdat[j++] = io_read8(pd->base + SSPDR); 219aca1545dSVictor Chong } 220aca1545dSVictor Chong 2219a2efe04SVictor Chong if (j < num_pkts) { 2229a2efe04SVictor Chong EMSG("Packets requested %zu, received %zu", 2239a2efe04SVictor Chong num_pkts, j); 2249a2efe04SVictor Chong return SPI_ERR_PKTCNT; 2259a2efe04SVictor Chong } 2269a2efe04SVictor Chong } 2279a2efe04SVictor Chong 2289a2efe04SVictor Chong return SPI_OK; 229aca1545dSVictor Chong } 230aca1545dSVictor Chong 231aca1545dSVictor Chong static void pl022_print_peri_id(struct pl022_data *pd __maybe_unused) 232aca1545dSVictor Chong { 233aca1545dSVictor Chong DMSG("Expected: 0x 22 10 ?4 00"); 234aca1545dSVictor Chong DMSG("Read: 0x %02x %02x %02x %02x", 235*918bb3a5SEtienne Carriere io_read8(pd->base + SSPPeriphID0), 236*918bb3a5SEtienne Carriere io_read8(pd->base + SSPPeriphID1), 237*918bb3a5SEtienne Carriere io_read8(pd->base + SSPPeriphID2), 238*918bb3a5SEtienne Carriere io_read8(pd->base + SSPPeriphID3)); 239aca1545dSVictor Chong } 240aca1545dSVictor Chong 241aca1545dSVictor Chong static void pl022_print_cell_id(struct pl022_data *pd __maybe_unused) 242aca1545dSVictor Chong { 243aca1545dSVictor Chong DMSG("Expected: 0x 0d f0 05 b1"); 244aca1545dSVictor Chong DMSG("Read: 0x %02x %02x %02x %02x", 245*918bb3a5SEtienne Carriere io_read8(pd->base + SSPPCellID0), 246*918bb3a5SEtienne Carriere io_read8(pd->base + SSPPCellID1), 247*918bb3a5SEtienne Carriere io_read8(pd->base + SSPPCellID2), 248*918bb3a5SEtienne Carriere io_read8(pd->base + SSPPCellID3)); 249aca1545dSVictor Chong } 250aca1545dSVictor Chong 251aca1545dSVictor Chong static void pl022_sanity_check(struct pl022_data *pd) 252aca1545dSVictor Chong { 253aca1545dSVictor Chong assert(pd); 254aca1545dSVictor Chong assert(pd->chip.ops); 25526128b8fSVictor Chong assert(pd->cs_control <= PL022_CS_CTRL_MANUAL); 25626128b8fSVictor Chong switch (pd->cs_control) { 25726128b8fSVictor Chong case PL022_CS_CTRL_AUTO_GPIO: 25826128b8fSVictor Chong assert(pd->cs_data.gpio_data.chip); 25926128b8fSVictor Chong assert(pd->cs_data.gpio_data.chip->ops); 26026128b8fSVictor Chong break; 26126128b8fSVictor Chong case PL022_CS_CTRL_CB: 26226128b8fSVictor Chong assert(pd->cs_data.cs_cb); 26326128b8fSVictor Chong break; 26426128b8fSVictor Chong default: 26526128b8fSVictor Chong break; 26626128b8fSVictor Chong } 267aca1545dSVictor Chong assert(pd->clk_hz); 268aca1545dSVictor Chong assert(pd->speed_hz && pd->speed_hz <= pd->clk_hz/2); 269aca1545dSVictor Chong assert(pd->mode <= SPI_MODE3); 270aca1545dSVictor Chong assert(pd->data_size_bits == 8 || pd->data_size_bits == 16); 271aca1545dSVictor Chong 272aca1545dSVictor Chong #ifdef PLATFORM_hikey 273aca1545dSVictor Chong DMSG("SSPB2BTRANS: Expected: 0x2. Read: 0x%x", 274*918bb3a5SEtienne Carriere io_read8(pd->base + SSPB2BTRANS)); 275aca1545dSVictor Chong #endif 276aca1545dSVictor Chong pl022_print_peri_id(pd); 277aca1545dSVictor Chong pl022_print_cell_id(pd); 278aca1545dSVictor Chong } 279aca1545dSVictor Chong 280aca1545dSVictor Chong static inline uint32_t pl022_calc_freq(struct pl022_data *pd, 281aca1545dSVictor Chong uint8_t cpsdvr, uint8_t scr) 282aca1545dSVictor Chong { 283aca1545dSVictor Chong return pd->clk_hz / (cpsdvr * (1 + scr)); 284aca1545dSVictor Chong } 285aca1545dSVictor Chong 28626128b8fSVictor Chong static void pl022_control_cs(struct spi_chip *chip, enum gpio_level value) 28726128b8fSVictor Chong { 28826128b8fSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 28926128b8fSVictor Chong 29026128b8fSVictor Chong switch (pd->cs_control) { 29126128b8fSVictor Chong case PL022_CS_CTRL_AUTO_GPIO: 292*918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_BSY) 29326128b8fSVictor Chong DMSG("pl022 busy - do NOT set CS!"); 294*918bb3a5SEtienne Carriere while (io_read8(pd->base + SSPSR) & SSPSR_BSY) 29526128b8fSVictor Chong ; 29626128b8fSVictor Chong DMSG("pl022 done - set CS!"); 29726128b8fSVictor Chong 29826128b8fSVictor Chong pd->cs_data.gpio_data.chip->ops->set_value( 29926128b8fSVictor Chong pd->cs_data.gpio_data.pin_num, value); 30026128b8fSVictor Chong break; 30126128b8fSVictor Chong case PL022_CS_CTRL_CB: 30226128b8fSVictor Chong pd->cs_data.cs_cb(value); 30326128b8fSVictor Chong break; 30426128b8fSVictor Chong default: 30526128b8fSVictor Chong break; 30626128b8fSVictor Chong } 30726128b8fSVictor Chong } 30826128b8fSVictor Chong 309aca1545dSVictor Chong static void pl022_calc_clk_divisors(struct pl022_data *pd, 310aca1545dSVictor Chong uint8_t *cpsdvr, uint8_t *scr) 311aca1545dSVictor Chong { 312aca1545dSVictor Chong unsigned int freq1 = 0; 313aca1545dSVictor Chong unsigned int freq2 = 0; 314aca1545dSVictor Chong uint8_t tmp_cpsdvr1; 315aca1545dSVictor Chong uint8_t tmp_scr1; 316aca1545dSVictor Chong uint8_t tmp_cpsdvr2 = 0; 317aca1545dSVictor Chong uint8_t tmp_scr2 = 0; 318aca1545dSVictor Chong 319aca1545dSVictor Chong for (tmp_scr1 = SSP_SCR_MIN; tmp_scr1 < SSP_SCR_MAX; tmp_scr1++) { 320aca1545dSVictor Chong for (tmp_cpsdvr1 = SSP_CPSDVR_MIN; tmp_cpsdvr1 < SSP_CPSDVR_MAX; 321aca1545dSVictor Chong tmp_cpsdvr1++) { 322aca1545dSVictor Chong freq1 = pl022_calc_freq(pd, tmp_cpsdvr1, tmp_scr1); 323aca1545dSVictor Chong if (freq1 == pd->speed_hz) 324aca1545dSVictor Chong goto done; 325aca1545dSVictor Chong else if (freq1 < pd->speed_hz) 326aca1545dSVictor Chong goto stage2; 327aca1545dSVictor Chong } 328aca1545dSVictor Chong } 329aca1545dSVictor Chong 330aca1545dSVictor Chong stage2: 331aca1545dSVictor Chong for (tmp_cpsdvr2 = SSP_CPSDVR_MIN; tmp_cpsdvr2 < SSP_CPSDVR_MAX; 332aca1545dSVictor Chong tmp_cpsdvr2++) { 333aca1545dSVictor Chong for (tmp_scr2 = SSP_SCR_MIN; tmp_scr2 < SSP_SCR_MAX; 334aca1545dSVictor Chong tmp_scr2++) { 335aca1545dSVictor Chong freq2 = pl022_calc_freq(pd, tmp_cpsdvr2, tmp_scr2); 336aca1545dSVictor Chong if (freq2 <= pd->speed_hz) 337aca1545dSVictor Chong goto done; 338aca1545dSVictor Chong } 339aca1545dSVictor Chong } 340aca1545dSVictor Chong 341aca1545dSVictor Chong done: 342aca1545dSVictor Chong if (freq1 >= freq2) { 343aca1545dSVictor Chong *cpsdvr = tmp_cpsdvr1; 344aca1545dSVictor Chong *scr = tmp_scr1; 345aca1545dSVictor Chong DMSG("speed: requested: %u, closest1: %u", 346aca1545dSVictor Chong pd->speed_hz, freq1); 347aca1545dSVictor Chong } else { 348aca1545dSVictor Chong *cpsdvr = tmp_cpsdvr2; 349aca1545dSVictor Chong *scr = tmp_scr2; 350aca1545dSVictor Chong DMSG("speed: requested: %u, closest2: %u", 351aca1545dSVictor Chong pd->speed_hz, freq2); 352aca1545dSVictor Chong } 353aca1545dSVictor Chong DMSG("CPSDVR: %u (0x%x), SCR: %u (0x%x)", 354aca1545dSVictor Chong *cpsdvr, *cpsdvr, *scr, *scr); 355aca1545dSVictor Chong } 356aca1545dSVictor Chong 357aca1545dSVictor Chong static void pl022_flush_fifo(struct pl022_data *pd) 358aca1545dSVictor Chong { 359aca1545dSVictor Chong uint32_t __maybe_unused rdat; 360aca1545dSVictor Chong 361aca1545dSVictor Chong do { 362*918bb3a5SEtienne Carriere while (io_read32(pd->base + SSPSR) & SSPSR_RNE) { 363*918bb3a5SEtienne Carriere rdat = io_read32(pd->base + SSPDR); 364aca1545dSVictor Chong DMSG("rdat: 0x%x", rdat); 365aca1545dSVictor Chong } 366*918bb3a5SEtienne Carriere } while (io_read32(pd->base + SSPSR) & SSPSR_BSY); 367aca1545dSVictor Chong } 368aca1545dSVictor Chong 3696356eeb2SVictor Chong static void pl022_configure(struct spi_chip *chip) 370aca1545dSVictor Chong { 371aca1545dSVictor Chong uint16_t mode; 372aca1545dSVictor Chong uint16_t data_size; 373aca1545dSVictor Chong uint8_t cpsdvr; 374aca1545dSVictor Chong uint8_t scr; 375aca1545dSVictor Chong uint8_t lbm; 3766356eeb2SVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 377aca1545dSVictor Chong 378aca1545dSVictor Chong pl022_sanity_check(pd); 37926128b8fSVictor Chong 38026128b8fSVictor Chong switch (pd->cs_control) { 38126128b8fSVictor Chong case PL022_CS_CTRL_AUTO_GPIO: 38226128b8fSVictor Chong DMSG("Use auto GPIO CS control"); 38326128b8fSVictor Chong DMSG("Mask/disable interrupt for CS GPIO"); 38426128b8fSVictor Chong pd->cs_data.gpio_data.chip->ops->set_interrupt( 38526128b8fSVictor Chong pd->cs_data.gpio_data.pin_num, 38626128b8fSVictor Chong GPIO_INTERRUPT_DISABLE); 38726128b8fSVictor Chong DMSG("Set CS GPIO dir to out"); 38826128b8fSVictor Chong pd->cs_data.gpio_data.chip->ops->set_direction( 38926128b8fSVictor Chong pd->cs_data.gpio_data.pin_num, 39026128b8fSVictor Chong GPIO_DIR_OUT); 39126128b8fSVictor Chong break; 39226128b8fSVictor Chong case PL022_CS_CTRL_CB: 39326128b8fSVictor Chong DMSG("Use registered CS callback"); 39426128b8fSVictor Chong break; 39526128b8fSVictor Chong case PL022_CS_CTRL_MANUAL: 39626128b8fSVictor Chong DMSG("Use manual CS control"); 39726128b8fSVictor Chong break; 39826128b8fSVictor Chong default: 39926128b8fSVictor Chong EMSG("Invalid CS control type: %d", pd->cs_control); 40026128b8fSVictor Chong panic(); 40126128b8fSVictor Chong } 40226128b8fSVictor Chong 40326128b8fSVictor Chong DMSG("Pull CS high"); 40426128b8fSVictor Chong pl022_control_cs(chip, GPIO_LEVEL_HIGH); 40526128b8fSVictor Chong 406aca1545dSVictor Chong pl022_calc_clk_divisors(pd, &cpsdvr, &scr); 407aca1545dSVictor Chong 408aca1545dSVictor Chong /* configure ssp based on platform settings */ 409aca1545dSVictor Chong switch (pd->mode) { 410aca1545dSVictor Chong case SPI_MODE0: 4112ff86f60SVictor Chong DMSG("SPI mode 0"); 4122ff86f60SVictor Chong mode = SSPCR0_SPO0 | SSPCR0_SPH0; 413aca1545dSVictor Chong break; 414aca1545dSVictor Chong case SPI_MODE1: 4152ff86f60SVictor Chong DMSG("SPI mode 1"); 4162ff86f60SVictor Chong mode = SSPCR0_SPO0 | SSPCR0_SPH1; 417aca1545dSVictor Chong break; 418aca1545dSVictor Chong case SPI_MODE2: 4192ff86f60SVictor Chong DMSG("SPI mode 2"); 4202ff86f60SVictor Chong mode = SSPCR0_SPO1 | SSPCR0_SPH0; 421aca1545dSVictor Chong break; 422aca1545dSVictor Chong case SPI_MODE3: 4232ff86f60SVictor Chong DMSG("SPI mode 3"); 4242ff86f60SVictor Chong mode = SSPCR0_SPO1 | SSPCR0_SPH1; 425aca1545dSVictor Chong break; 426aca1545dSVictor Chong default: 427aca1545dSVictor Chong EMSG("Invalid SPI mode: %u", pd->mode); 428aca1545dSVictor Chong panic(); 429aca1545dSVictor Chong } 430aca1545dSVictor Chong 431aca1545dSVictor Chong switch (pd->data_size_bits) { 432aca1545dSVictor Chong case 8: 433aca1545dSVictor Chong DMSG("Data size: 8"); 4342ff86f60SVictor Chong data_size = SSPCR0_DSS_8BIT; 435aca1545dSVictor Chong break; 436aca1545dSVictor Chong case 16: 437aca1545dSVictor Chong DMSG("Data size: 16"); 4382ff86f60SVictor Chong data_size = SSPCR0_DSS_16BIT; 439aca1545dSVictor Chong break; 440aca1545dSVictor Chong default: 441aca1545dSVictor Chong EMSG("Unsupported data size: %u bits", pd->data_size_bits); 442aca1545dSVictor Chong panic(); 443aca1545dSVictor Chong } 444aca1545dSVictor Chong 445aca1545dSVictor Chong if (pd->loopback) { 446aca1545dSVictor Chong DMSG("Starting in loopback mode!"); 447aca1545dSVictor Chong lbm = SSPCR1_LBM_YES; 448aca1545dSVictor Chong } else { 449aca1545dSVictor Chong DMSG("Starting in regular (non-loopback) mode!"); 450aca1545dSVictor Chong lbm = SSPCR1_LBM_NO; 451aca1545dSVictor Chong } 452aca1545dSVictor Chong 45326128b8fSVictor Chong DMSG("Set Serial Clock Rate (SCR), SPI mode (phase and clock)"); 45426128b8fSVictor Chong DMSG("Set frame format (SPI) and data size (8- or 16-bit)"); 455aca1545dSVictor Chong io_mask16(pd->base + SSPCR0, SHIFT_U32(scr, 8) | mode | SSPCR0_FRF_SPI | 456aca1545dSVictor Chong data_size, MASK_16); 457aca1545dSVictor Chong 45826128b8fSVictor Chong DMSG("Set master mode, disable SSP, set loopback mode"); 459aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SOD_DISABLE | SSPCR1_MS_MASTER | 460aca1545dSVictor Chong SSPCR1_SSE_DISABLE | lbm, MASK_4); 461aca1545dSVictor Chong 46226128b8fSVictor Chong DMSG("Set clock prescale"); 463aca1545dSVictor Chong io_mask8(pd->base + SSPCPSR, cpsdvr, SSPCPSR_CPSDVR); 464aca1545dSVictor Chong 46526128b8fSVictor Chong DMSG("Disable interrupts"); 466aca1545dSVictor Chong io_mask8(pd->base + SSPIMSC, 0, MASK_4); 467aca1545dSVictor Chong 46826128b8fSVictor Chong DMSG("Clear interrupts"); 4699a2efe04SVictor Chong io_mask8(pd->base + SSPICR, SSPICR_RORIC | SSPICR_RTIC, 4709a2efe04SVictor Chong SSPICR_RORIC | SSPICR_RTIC); 4719a2efe04SVictor Chong 47226128b8fSVictor Chong DMSG("Empty FIFO before starting"); 4736356eeb2SVictor Chong pl022_flush_fifo(pd); 474aca1545dSVictor Chong } 475aca1545dSVictor Chong 4766356eeb2SVictor Chong static void pl022_start(struct spi_chip *chip) 477aca1545dSVictor Chong { 4786356eeb2SVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 479aca1545dSVictor Chong 48026128b8fSVictor Chong DMSG("Enable SSP"); 481aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SSE_ENABLE, SSPCR1_SSE); 48226128b8fSVictor Chong 48326128b8fSVictor Chong pl022_control_cs(chip, GPIO_LEVEL_LOW); 484aca1545dSVictor Chong } 485aca1545dSVictor Chong 4866356eeb2SVictor Chong static void pl022_end(struct spi_chip *chip) 487aca1545dSVictor Chong { 4886356eeb2SVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip); 4896356eeb2SVictor Chong 49026128b8fSVictor Chong pl022_control_cs(chip, GPIO_LEVEL_HIGH); 49126128b8fSVictor Chong 49226128b8fSVictor Chong DMSG("Disable SSP"); 493aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SSE_DISABLE, SSPCR1_SSE); 494aca1545dSVictor Chong } 495aca1545dSVictor Chong 4966356eeb2SVictor Chong static const struct spi_ops pl022_ops = { 4976356eeb2SVictor Chong .configure = pl022_configure, 4986356eeb2SVictor Chong .start = pl022_start, 4996356eeb2SVictor Chong .txrx8 = pl022_txrx8, 5006356eeb2SVictor Chong .txrx16 = pl022_txrx16, 5016356eeb2SVictor Chong .end = pl022_end, 5026356eeb2SVictor Chong }; 5036356eeb2SVictor Chong 5046356eeb2SVictor Chong void pl022_init(struct pl022_data *pd) 5056356eeb2SVictor Chong { 5066356eeb2SVictor Chong assert(pd); 5076356eeb2SVictor Chong pd->chip.ops = &pl022_ops; 5086356eeb2SVictor Chong } 509