mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
armv7/exynos5420: Revise SPI open/close/reset procedure.
The original Exynos SPI open/close procedure was copied from U-Boot SPL with some assumptions that only works in SPL stage. For example, it tries to always work in 4-byte transmission mode with only RX data is swapped, and claims a packet for initial address command (and with incorrect size). This commit revises open/close and reset so only the required SPI registers are configured. Change-Id: Ieba1f03d80a8949c39a6658218831ded39853744 Signed-off-by: Hung-Te Lin <hungte@chromium.org> Signed-off-by: Gabe Black <gabeblack@chromium.org> Reviewed-on: http://review.coreboot.org/3712 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
parent
ed1742cafe
commit
cab3621446
1 changed files with 39 additions and 37 deletions
|
@ -102,6 +102,26 @@ void spi_cs_deactivate(struct spi_slave *slave)
|
||||||
setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);
|
setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void exynos_spi_soft_reset(struct exynos_spi *regs)
|
||||||
|
{
|
||||||
|
/* The soft reset clears only FIFO and status register.
|
||||||
|
* All special function registers are not changed. */
|
||||||
|
setbits_le32(®s->ch_cfg, SPI_CH_RST);
|
||||||
|
clrbits_le32(®s->ch_cfg, SPI_CH_RST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void exynos_spi_flush_fifo(struct exynos_spi *regs)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Flush spi tx, rx fifos and reset the SPI controller
|
||||||
|
* and clear rx/tx channel
|
||||||
|
*/
|
||||||
|
clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON);
|
||||||
|
clrbits_le32(®s->ch_cfg, SPI_CH_HS_EN);
|
||||||
|
exynos_spi_soft_reset(regs);
|
||||||
|
setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON);
|
||||||
|
}
|
||||||
|
|
||||||
static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
|
static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
|
||||||
void *dinp, void const *doutp, int i)
|
void *dinp, void const *doutp, int i)
|
||||||
{
|
{
|
||||||
|
@ -114,8 +134,7 @@ static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
|
||||||
ASSERT(todo % 4 == 0);
|
ASSERT(todo % 4 == 0);
|
||||||
|
|
||||||
out_bytes = in_bytes = todo;
|
out_bytes = in_bytes = todo;
|
||||||
setbits_le32(®s->ch_cfg, SPI_CH_RST);
|
exynos_spi_soft_reset(regs);
|
||||||
clrbits_le32(®s->ch_cfg, SPI_CH_RST);
|
|
||||||
writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, ®s->pkt_cnt);
|
writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, ®s->pkt_cnt);
|
||||||
|
|
||||||
while (in_bytes) {
|
while (in_bytes) {
|
||||||
|
@ -143,35 +162,27 @@ static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set up SPI channel */
|
|
||||||
int spi_claim_bus(struct spi_slave *slave)
|
int spi_claim_bus(struct spi_slave *slave)
|
||||||
{
|
{
|
||||||
struct exynos_spi_slave *espi = to_exynos_spi(slave);
|
struct exynos_spi_slave *espi = to_exynos_spi(slave);
|
||||||
struct exynos_spi *regs = espi->regs;
|
struct exynos_spi *regs = espi->regs;
|
||||||
|
|
||||||
/* set the spi1 GPIO */
|
exynos_spi_flush_fifo(regs);
|
||||||
|
|
||||||
/* set pktcnt and enable it */
|
// Select Active High Clock, Format A (SCP 30.2.1.8).
|
||||||
writel(4 | SPI_PACKET_CNT_EN, ®s->pkt_cnt);
|
clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L | SPI_CH_CPHA_B);
|
||||||
/* set FB_CLK_SEL */
|
|
||||||
|
// Set FeedBack Clock Selection.
|
||||||
writel(SPI_FB_DELAY_180, ®s->fb_clk);
|
writel(SPI_FB_DELAY_180, ®s->fb_clk);
|
||||||
/* set CH_WIDTH and BUS_WIDTH as word */
|
|
||||||
setbits_le32(®s->mode_cfg,
|
|
||||||
SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
|
|
||||||
clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */
|
|
||||||
|
|
||||||
/* clear rx and tx channel if set priveously */
|
// HIGH speed is required for Tx/Rx to work in 50MHz (SCP 30.2.1.6).
|
||||||
clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON);
|
if (espi->half_duplex) {
|
||||||
|
clrbits_le32(®s->ch_cfg, SPI_CH_HS_EN);
|
||||||
setbits_le32(®s->swap_cfg,
|
printk(BIOS_DEBUG, "%s: LOW speed.\n", __func__);
|
||||||
SPI_RX_SWAP_EN | SPI_RX_BYTE_SWAP | SPI_RX_HWORD_SWAP);
|
} else {
|
||||||
|
setbits_le32(®s->ch_cfg, SPI_CH_HS_EN);
|
||||||
/* do a soft reset */
|
printk(BIOS_DEBUG, "%s: HIGH speed.\n", __func__);
|
||||||
setbits_le32(®s->ch_cfg, SPI_CH_RST);
|
}
|
||||||
clrbits_le32(®s->ch_cfg, SPI_CH_RST);
|
|
||||||
|
|
||||||
/* now set rx and tx channel ON */
|
|
||||||
setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,21 +220,12 @@ static int exynos_spi_read(struct spi_slave *slave, void *dest, uint32_t len,
|
||||||
void spi_release_bus(struct spi_slave *slave)
|
void spi_release_bus(struct spi_slave *slave)
|
||||||
{
|
{
|
||||||
struct exynos_spi *regs = to_exynos_spi(slave)->regs;
|
struct exynos_spi *regs = to_exynos_spi(slave)->regs;
|
||||||
/*
|
/* Reset swap mode to make sure no one relying on default values (Ex,
|
||||||
* Let put controller mode to BYTE as
|
* payload or kernel) will go wrong. */
|
||||||
* SPI driver does not support WORD mode yet
|
clrbits_le32(®s->mode_cfg, (SPI_MODE_CH_WIDTH_WORD |
|
||||||
*/
|
SPI_MODE_BUS_WIDTH_WORD));
|
||||||
clrbits_le32(®s->mode_cfg,
|
|
||||||
SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
|
|
||||||
writel(0, ®s->swap_cfg);
|
writel(0, ®s->swap_cfg);
|
||||||
|
exynos_spi_flush_fifo(regs);
|
||||||
/*
|
|
||||||
* Flush spi tx, rx fifos and reset the SPI controller
|
|
||||||
* and clear rx/tx channel
|
|
||||||
*/
|
|
||||||
clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
|
|
||||||
clrbits_le32(®s->ch_cfg, SPI_CH_RST);
|
|
||||||
clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI as CBFS media.
|
// SPI as CBFS media.
|
||||||
|
|
Loading…
Add table
Reference in a new issue