diff options
Diffstat (limited to 'src/soc/marvell/armada38x/spi.c')
-rw-r--r-- | src/soc/marvell/armada38x/spi.c | 488 |
1 files changed, 0 insertions, 488 deletions
diff --git a/src/soc/marvell/armada38x/spi.c b/src/soc/marvell/armada38x/spi.c deleted file mode 100644 index 47631f4c69..0000000000 --- a/src/soc/marvell/armada38x/spi.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2015 Marvell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <arch/io.h> -#include <delay.h> -#include <spi_flash.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <console/console.h> -#include <soc/common.h> -#include <soc/clock.h> - -/****************************************************************************** -base type define -*******************************************************************************/ -#define MV_SPI_REG_READ mrvl_reg_read -#define MV_SPI_REG_WRITE mrvl_reg_write -#define MV_SPI_REG_BIT_SET mrvl_reg_bit_set -#define MV_SPI_REG_BIT_RESET mrvl_reg_bit_reset - -#define MV_SPI_REGS_OFFSET(unit) (0x10600 + (unit * 0x80)) -#define MV_SPI_REGS_BASE(unit) (MV_SPI_REGS_OFFSET(unit)) -#define MV_SPI_IF_CONFIG_REG(spi_id) (MV_SPI_REGS_BASE(spi_id) + 0x04) -#define MV_SPI_SPR_OFFSET 0 -#define MV_SPI_SPR_MASK (0xF << MV_SPI_SPR_OFFSET) -#define MV_SPI_SPPR_0_OFFSET 4 -#define MV_SPI_SPPR_0_MASK (0x1 << MV_SPI_SPPR_0_OFFSET) -#define MV_SPI_SPPR_HI_OFFSET 6 -#define MV_SPI_SPPR_HI_MASK (0x3 << MV_SPI_SPPR_HI_OFFSET) - -#define MV_SPI_BYTE_LENGTH_OFFSET 5 /* bit 5 */ -#define MV_SPI_BYTE_LENGTH_MASK (0x1 << MV_SPI_BYTE_LENGTH_OFFSET) - -#define MV_SPI_IF_CTRL_REG(spi_id) (MV_SPI_REGS_BASE(spi_id) + 0x00) -#define MV_SPI_CS_ENABLE_OFFSET 0 /* bit 0 */ -#define MV_SPI_CS_ENABLE_MASK (0x1 << MV_SPI_CS_ENABLE_OFFSET) - -#define MV_SPI_CS_NUM_OFFSET 2 -#define MV_SPI_CS_NUM_MASK (0x7 << MV_SPI_CS_NUM_OFFSET) -#define MV_SPI_CPOL_OFFSET 11 -#define MV_SPI_CPOL_MASK (0x1 << MV_SPI_CPOL_OFFSET) -#define MV_SPI_CPHA_OFFSET 12 -#define MV_SPI_CPHA_MASK (0x1 << MV_SPI_CPHA_OFFSET) -#define MV_SPI_TXLSBF_OFFSET 13 -#define MV_SPI_TXLSBF_MASK (0x1 << MV_SPI_TXLSBF_OFFSET) -#define MV_SPI_RXLSBF_OFFSET 14 -#define MV_SPI_RXLSBF_MASK (0x1 << MV_SPI_RXLSBF_OFFSET) - -/* SPI transfer flags */ -#define SPI_XFER_BEGIN 0x01 -#define SPI_XFER_END 0x02 - -#define MV_SPI_INT_CAUSE_REG(spi_id) (MV_SPI_REGS_BASE(spi_id) + 0x10) -#define MV_SPI_DATA_OUT_REG(spi_id) (MV_SPI_REGS_BASE(spi_id) + 0x08) -#define MV_SPI_WAIT_RDY_MAX_LOOP 100000 -#define MV_SPI_DATA_IN_REG(spi_id) (MV_SPI_REGS_BASE(spi_id) + 0x0c) - -#define MV_SPI_TMNG_PARAMS_REG(spi_id) (MV_SPI_REGS_BASE(spi_id) + 0x18) -#define MV_SPI_TMISO_SAMPLE_OFFSET 6 -#define MV_SPI_TMISO_SAMPLE_MASK (0x3 << MV_SPI_TMISO_SAMPLE_OFFSET) - -#define CONFIG_ENV_SPI_MAX_HZ 50000000 -#define CONFIG_SF_DEFAULT_SPEED CONFIG_ENV_SPI_MAX_HZ - -#define CMD_READ_ARRAY_FAST 0x0b - -/****************************************************************************** -base type define end -*******************************************************************************/ - -/****************************************************************************** -struct define -*******************************************************************************/ -typedef enum { - SPI_TYPE_FLASH = 0, - SPI_TYPE_SLIC_ZARLINK_SILABS, - SPI_TYPE_SLIC_LANTIQ, - SPI_TYPE_SLIC_ZSI, - SPI_TYPE_SLIC_ISI -} MV_SPI_TYPE; - -typedef struct { - unsigned short ctrl_model; - unsigned int tclk; -} MV_SPI_HAL_DATA; - -typedef struct { - int clock_pol_low; - enum { SPI_CLK_HALF_CYC, SPI_CLK_BEGIN_CYC } clock_phase; - int tx_msb_first; - int rx_msb_first; -} MV_SPI_IF_PARAMS; - -typedef struct { - /* Does this device support 16 bits access */ - int en16_bit; - /* should we assert / disassert CS for each byte we read / write */ - int byte_cs_asrt; - int clock_pol_low; - unsigned int baud_rate; - unsigned int clk_phase; -} MV_SPI_TYPE_INFO; - -/****************************************************************************** -struct define end -*******************************************************************************/ - -/****************************************************************************** -param define -*******************************************************************************/ -static MV_SPI_HAL_DATA spi_hal_data; -static MV_SPI_TYPE_INFO *curr_spi_info = NULL; -static MV_SPI_TYPE_INFO spi_types[] = { {.en16_bit = MV_TRUE, - .clock_pol_low = MV_TRUE, - .byte_cs_asrt = MV_FALSE, - .baud_rate = (20 << 20), /* 20_m */ - .clk_phase = SPI_CLK_BEGIN_CYC}, - {.en16_bit = MV_FALSE, - .clock_pol_low = MV_TRUE, - .byte_cs_asrt = MV_TRUE, - .baud_rate = 0x00800000, - .clk_phase = SPI_CLK_BEGIN_CYC}, - {.en16_bit = MV_FALSE, - .clock_pol_low = MV_TRUE, - .byte_cs_asrt = MV_FALSE, - .baud_rate = 0x00800000, - .clk_phase = SPI_CLK_BEGIN_CYC}, - {.en16_bit = MV_FALSE, - .clock_pol_low = MV_TRUE, - .byte_cs_asrt = MV_TRUE, - .baud_rate = 0x00800000, - .clk_phase = SPI_CLK_HALF_CYC}, - {.en16_bit = MV_FALSE, - .clock_pol_low = MV_FALSE, - .byte_cs_asrt = MV_TRUE, - .baud_rate = 0x00200000, - .clk_phase = SPI_CLK_HALF_CYC} }; - -/****************************************************************************** -param define end -*******************************************************************************/ - -static int mv_spi_baud_rate_set(unsigned char spi_id, - unsigned int serial_baud_rate); -static void mv_spi_cs_deassert(unsigned char spi_id); -static int mv_spi_cs_set(unsigned char spi_id, unsigned char cs_id); -static int mv_spi_if_config_set(unsigned char spi_id, - MV_SPI_IF_PARAMS *if_params); -static int mv_spi_params_set(unsigned char spi_id, - unsigned char cs_id, - MV_SPI_TYPE type); -static int mv_spi_init(unsigned char spi_id, - unsigned char cs_id, - unsigned int serial_baud_rate, - MV_SPI_HAL_DATA *hal_data); -static int mv_spi_sys_init(unsigned char spi_id, - unsigned char cs_id, - unsigned int serial_baud_rate); -static void mv_spi_cs_assert(unsigned char spi_id); -static int mv_spi_8bit_data_tx_rx(unsigned char spi_id, - unsigned char tx_data, - unsigned char *p_rx_data); - -int mv_spi_baud_rate_set(unsigned char spi_id, unsigned int serial_baud_rate) -{ - unsigned int spr, sppr; - unsigned int divider; - unsigned int best_spr = 0, best_sppr = 0; - unsigned char exact_match = 0; - unsigned int min_baud_offset = 0xFFFFFFFF; - unsigned int cpu_clk = spi_hal_data.tclk; /*mv_cpu_pclk_get();*/ - unsigned int temp_reg; - - assert(cpu_clk != serial_baud_rate); - /* Find the best prescale configuration - less or equal */ - for (spr = 1; spr <= 15; spr++) { - for (sppr = 0; sppr <= 7; sppr++) { - divider = spr * (1 << sppr); - /* check for higher - irrelevant */ - if ((cpu_clk / divider) > serial_baud_rate) - continue; - - /* check for exact fit */ - if ((cpu_clk / divider) == serial_baud_rate) { - best_spr = spr; - best_sppr = sppr; - exact_match = 1; - break; - } - - /* check if this is better than the previous one */ - if ((serial_baud_rate - (cpu_clk / divider)) < - min_baud_offset) { - min_baud_offset = - serial_baud_rate - cpu_clk / divider; - best_spr = spr; - best_sppr = sppr; - } - } - - if (exact_match == 1) - break; - } - - if (best_spr == 0) { - printk(BIOS_INFO, "%s ERROR: SPI baud rate prescale error!\n", - __func__); - return MV_OUT_OF_RANGE; - } - - /* configure the Prescale */ - temp_reg = MV_SPI_REG_READ(MV_SPI_IF_CONFIG_REG(spi_id)) & - ~(MV_SPI_SPR_MASK | MV_SPI_SPPR_0_MASK | MV_SPI_SPPR_HI_MASK); - temp_reg |= ((best_spr << MV_SPI_SPR_OFFSET) | - ((best_sppr & 0x1) << MV_SPI_SPPR_0_OFFSET) | - ((best_sppr >> 1) << MV_SPI_SPPR_HI_OFFSET)); - MV_SPI_REG_WRITE(MV_SPI_IF_CONFIG_REG(spi_id), temp_reg); - - return MV_OK; -} - -void mv_spi_cs_deassert(unsigned char spi_id) -{ - MV_SPI_REG_BIT_RESET(MV_SPI_IF_CTRL_REG(spi_id), MV_SPI_CS_ENABLE_MASK); -} - -int mv_spi_cs_set(unsigned char spi_id, unsigned char cs_id) -{ - unsigned int ctrl_reg; - static unsigned char last_cs_id = 0xFF; - static unsigned char last_spi_id = 0xFF; - - if (cs_id > 7) - return MV_BAD_PARAM; - - if ((last_spi_id == spi_id) && (last_cs_id == cs_id)) - return MV_OK; - - ctrl_reg = MV_SPI_REG_READ(MV_SPI_IF_CTRL_REG(spi_id)); - ctrl_reg &= ~MV_SPI_CS_NUM_MASK; - ctrl_reg |= (cs_id << MV_SPI_CS_NUM_OFFSET); - MV_SPI_REG_WRITE(MV_SPI_IF_CTRL_REG(spi_id), ctrl_reg); - - last_spi_id = spi_id; - last_cs_id = cs_id; - - return MV_OK; -} - -int mv_spi_if_config_set(unsigned char spi_id, MV_SPI_IF_PARAMS *if_params) -{ - unsigned int ctrl_reg; - - ctrl_reg = MV_SPI_REG_READ(MV_SPI_IF_CONFIG_REG(spi_id)); - - /* Set Clock Polarity */ - ctrl_reg &= ~(MV_SPI_CPOL_MASK | MV_SPI_CPHA_MASK | MV_SPI_TXLSBF_MASK | - MV_SPI_RXLSBF_MASK); - if (if_params->clock_pol_low) - ctrl_reg |= MV_SPI_CPOL_MASK; - - if (if_params->clock_phase == SPI_CLK_BEGIN_CYC) - ctrl_reg |= MV_SPI_CPHA_MASK; - - if (if_params->tx_msb_first) - ctrl_reg |= MV_SPI_TXLSBF_MASK; - - if (if_params->rx_msb_first) - ctrl_reg |= MV_SPI_RXLSBF_MASK; - - MV_SPI_REG_WRITE(MV_SPI_IF_CONFIG_REG(spi_id), ctrl_reg); - - return MV_OK; -} - -int mv_spi_params_set(unsigned char spi_id, - unsigned char cs_id, - MV_SPI_TYPE type) -{ - MV_SPI_IF_PARAMS if_params; - - if (MV_OK != mv_spi_cs_set(spi_id, cs_id)) { - printk(BIOS_INFO, "Error, setting SPI CS failed\n"); - return MV_ERROR; - } - - if (curr_spi_info != (&(spi_types[type]))) { - curr_spi_info = &(spi_types[type]); - mv_spi_baud_rate_set(spi_id, curr_spi_info->baud_rate); - - if_params.clock_pol_low = curr_spi_info->clock_pol_low; - if_params.clock_phase = curr_spi_info->clk_phase; - if_params.tx_msb_first = MV_FALSE; - if_params.rx_msb_first = MV_FALSE; - mv_spi_if_config_set(spi_id, &if_params); - } - - return MV_OK; -} - -int mv_spi_init(unsigned char spi_id, - unsigned char cs_id, - unsigned int serial_baud_rate, - MV_SPI_HAL_DATA *hal_data) -{ - int ret; - unsigned int timing_reg; - - spi_hal_data.ctrl_model = hal_data->ctrl_model; - spi_hal_data.tclk = hal_data->tclk; - - /* Set the serial clock */ - ret = mv_spi_baud_rate_set(spi_id, serial_baud_rate); - if (ret != MV_OK) - return ret; - - /* Configure the default SPI mode to be 8bit */ - MV_SPI_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG(spi_id), - MV_SPI_BYTE_LENGTH_MASK); - - timing_reg = MV_SPI_REG_READ(MV_SPI_TMNG_PARAMS_REG(spi_id)); - timing_reg &= ~MV_SPI_TMISO_SAMPLE_MASK; - timing_reg |= (0x2) << MV_SPI_TMISO_SAMPLE_OFFSET; - MV_SPI_REG_WRITE(MV_SPI_TMNG_PARAMS_REG(spi_id), timing_reg); - - /* Verify that the CS is deasserted */ - mv_spi_cs_deassert(spi_id); - - mv_spi_params_set(spi_id, cs_id, SPI_TYPE_FLASH); - - return MV_OK; -} - -int mv_spi_sys_init(unsigned char spi_id, - unsigned char cs_id, - unsigned int serial_baud_rate) -{ - MV_SPI_HAL_DATA hal_data; - - hal_data.ctrl_model = MV_6810_DEV_ID; - hal_data.tclk = mv_tclk_get(); - - return mv_spi_init(spi_id, cs_id, serial_baud_rate, &hal_data); -} - -void mv_spi_cs_assert(unsigned char spi_id) -{ - MV_SPI_REG_BIT_SET(MV_SPI_IF_CTRL_REG(spi_id), MV_SPI_CS_ENABLE_MASK); -} - -int mv_spi_8bit_data_tx_rx(unsigned char spi_id, - unsigned char tx_data, - unsigned char *p_rx_data) -{ - unsigned int i; - int ready = MV_FALSE; - - if (curr_spi_info->byte_cs_asrt) - mv_spi_cs_assert(spi_id); - - /* First clear the bit in the interrupt cause register */ - MV_SPI_REG_WRITE(MV_SPI_INT_CAUSE_REG(spi_id), 0x0); - - /* Transmit data */ - MV_SPI_REG_WRITE(MV_SPI_DATA_OUT_REG(spi_id), tx_data); - - /* wait with timeout for memory ready */ - for (i = 0; i < MV_SPI_WAIT_RDY_MAX_LOOP; i++) { - if (MV_SPI_REG_READ(MV_SPI_INT_CAUSE_REG(spi_id))) { - ready = MV_TRUE; - break; - } - } - - if (!ready) { - if (curr_spi_info->byte_cs_asrt) { - mv_spi_cs_deassert(spi_id); - /* WA to compansate Zarlink SLIC CS off time */ - udelay(4); - } - return MV_TIMEOUT; - } - - /* check that the RX data is needed */ - if (p_rx_data) - *p_rx_data = MV_SPI_REG_READ(MV_SPI_DATA_IN_REG(spi_id)); - - if (curr_spi_info->byte_cs_asrt) { - mv_spi_cs_deassert(spi_id); - /* WA to compansate Zarlink SLIC CS off time */ - udelay(4); - } - - return MV_OK; -} - -static int mrvl_spi_xfer(const struct spi_slave *slave, - size_t bitlen, - const void *dout, - void *din) -{ - int ret; - unsigned char *pdout = (unsigned char *)dout; - unsigned char *pdin = (unsigned char *)din; - int tmp_bitlen = bitlen; - unsigned char tmp_dout = 0; - - /* Verify that the SPI mode is in 8bit mode */ - MV_SPI_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG(slave->bus), - MV_SPI_BYTE_LENGTH_MASK); - - while (tmp_bitlen > 0) { - if (pdout) - tmp_dout = (*pdout) & 0xff; - - /* Transmitted and wait for the transfer to be completed */ - ret = mv_spi_8bit_data_tx_rx(slave->bus, tmp_dout, pdin); - if (ret != MV_OK) - return ret; - - /* increment the pointers */ - if (pdin) - pdin++; - if (pdout) - pdout++; - - tmp_bitlen -= 8; - } - return 0; -} - -static int spi_ctrlr_claim_bus(const struct spi_slave *slave) -{ - mv_spi_cs_set(slave->bus, slave->cs); - mv_spi_cs_assert(slave->bus); - return 0; -} - -static void spi_ctrlr_release_bus(const struct spi_slave *slave) -{ - mv_spi_cs_deassert(slave->bus); -} - -static int spi_ctrlr_xfer(const struct spi_slave *slave, - const void *dout, - size_t out_bytes, - void *din, - size_t in_bytes) -{ - int ret = -1; - - if (out_bytes) - ret = mrvl_spi_xfer(slave, out_bytes * 8, dout, din); - else if (in_bytes) - ret = mrvl_spi_xfer(slave, in_bytes * 8, dout, din); - else - die("Unexpected condition in spi_xfer\n"); - return ret; -} - -static const spi_ctrlr spi_ctrlr = { - .claim_bus = spi_ctrlr_claim_bus, - .release_bus = spi_ctrlr_release_bus, - .xfer = spi_ctrlr_xfer, - .max_xfer_size = SPI_CTRLR_DEFAULT_MAX_XFER_SIZE, -}; - -int spi_setup_slave(unsigned int bus, unsigned int cs, struct spi_slave *slave) -{ - slave->bus = bus; - slave->cs = cs; - slave->ctrlr = &spi_ctrlr; - mv_spi_sys_init(bus, cs, CONFIG_SF_DEFAULT_SPEED); - return 0; -} |