Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 51 additions & 119 deletions fel-spiflash.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,18 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val);
#define PB (1)
#define PC (2)

#define CCM_SPI0_CLK (0x01C20000 + 0xA0)
#define CCM_AHB_GATING0 (0x01C20000 + 0x60)
#define CCM_SPI0_CLK_OFF 0xa0
#define CCM_AHB_GATING0_OFF 0x60
#define CCM_AHB_GATE_SPI0 (1 << 20)
#define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0)
#define SUN6I_BUS_SOFT_RST_REG0_OFF 0x2c0
#define SUN6I_SPI0_RST (1 << 20)
#define SUNIV_PLL6_CTL (0x01c20000 + 0x28)
#define SUNIV_AHB_APB_CFG (0x01c20000 + 0x54)
#define SUNIV_PLL6_CTL_OFF 0x28
#define SUNIV_AHB_APB_CFG_OFF 0x54

#define H6_CCM_SPI0_CLK (0x03001000 + 0x940)
#define H6_CCM_SPI_BGR (0x03001000 + 0x96C)
#define H6_CCM_SPI0_CLK_OFF 0x940
#define H6_CCM_SPI_BGR_OFF 0x96c
#define H6_CCM_SPI0_GATE_RESET (1 << 0 | 1 << 16)

#define SUNIV_GPC_SPI0 (2)
#define SUNXI_GPC_SPI0 (3)
#define SUN50I_GPC_SPI0 (4)

#define SUN4I_CTL_ENABLE (1 << 0)
#define SUN4I_CTL_MASTER (1 << 1)
#define SUN4I_CTL_TF_RST (1 << 8)
Expand Down Expand Up @@ -122,38 +118,9 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val);
#define CCM_SPI0_CLK_DIV_BY_6 (0x1002)
#define CCM_SPI0_CLK_DIV_BY_32 (0x100f)

static uint32_t gpio_base(feldev_handle *dev)
{
soc_info_t *soc_info = dev->soc_info;
switch (soc_info->soc_id) {
case 0x1816: /* V536 */
case 0x1817: /* V831 */
case 0x1728: /* H6 */
case 0x1823: /* H616 */
return 0x0300B000;
default:
return 0x01C20800;
}
}

static uint32_t spi_base(feldev_handle *dev)
{
soc_info_t *soc_info = dev->soc_info;
switch (soc_info->soc_id) {
case 0x1623: /* A10 */
case 0x1625: /* A13 */
case 0x1651: /* A20 */
case 0x1663: /* F1C100s */
case 0x1701: /* R40 */
return 0x01C05000;
case 0x1816: /* V536 */
case 0x1817: /* V831 */
case 0x1728: /* H6 */
case 0x1823: /* H616 */
return 0x05010000;
default:
return 0x01C68000;
}
return dev->soc_info->spi_base;
}

/*
Expand All @@ -162,13 +129,21 @@ static uint32_t spi_base(feldev_handle *dev)
static void gpio_set_cfgpin(feldev_handle *dev, int port_num, int pin_num,
int val)
{
uint32_t port_base = gpio_base(dev) + port_num * 0x24;
uint32_t cfg_reg = port_base + 4 * (pin_num / 8);
uint32_t pin_idx = pin_num % 8;
uint32_t x = readl(cfg_reg);
x &= ~(0x7 << (pin_idx * 4));
x |= val << (pin_idx * 4);
writel(x, cfg_reg);
uint32_t cfg_reg;
uint32_t pin_idx = pin_num % 8;
uint32_t reg;

cfg_reg = dev->soc_info->gpio_base;
if (dev->soc_info->flags & GPIO_NCAT2)
cfg_reg += port_num * 0x30;
else
cfg_reg += port_num * 0x24;
cfg_reg += 4 * (pin_num / 8);

reg = readl(cfg_reg);
reg &= ~(0xf << (pin_idx * 4));
reg |= val << (pin_idx * 4);
writel(reg, cfg_reg);
}

static bool spi_is_sun6i(feldev_handle *dev)
Expand All @@ -184,18 +159,12 @@ static bool spi_is_sun6i(feldev_handle *dev)
}
}

static bool soc_is_h6_style(feldev_handle *dev)
/* Extract a pin number from the packed representation (one byte per pin) */
static uint8_t spi_pin(soc_info_t *soc_info, int pin)
{
soc_info_t *soc_info = dev->soc_info;
switch (soc_info->soc_id) {
case 0x1816: /* V536 */
case 0x1817: /* V831 */
case 0x1728: /* H6 */
case 0x1823: /* H616 */
return true;
default:
return false;
}
int shift = (pin - 1) * 8;

return (soc_info->spi_pins >> shift) & 0xff;
}

/*
Expand All @@ -205,81 +174,42 @@ static bool spi0_init(feldev_handle *dev)
{
uint32_t reg_val;
soc_info_t *soc_info = dev->soc_info;
uint32_t ccu_base;

if (!soc_info) {
printf("Unable to fetch device information. "
"Possibly unknown device.\n");
return false;
}

/* Setup SPI0 pins muxing */
switch (soc_info->soc_id) {
case 0x1663: /* Allwinner F1C100s/F1C600/R6/F1C100A/F1C500 */
gpio_set_cfgpin(dev, PC, 0, SUNIV_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 1, SUNIV_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 2, SUNIV_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 3, SUNIV_GPC_SPI0);
break;
case 0x1625: /* Allwinner A13 */
case 0x1680: /* Allwinner H3 */
case 0x1681: /* Allwinner V3s */
case 0x1718: /* Allwinner H5 */
gpio_set_cfgpin(dev, PC, 0, SUNXI_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 1, SUNXI_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 2, SUNXI_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 3, SUNXI_GPC_SPI0);
break;
case 0x1623: /* Allwinner A10 */
case 0x1651: /* Allwinner A20 */
case 0x1701: /* Allwinner R40 */
gpio_set_cfgpin(dev, PC, 0, SUNXI_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 1, SUNXI_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 2, SUNXI_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 23, SUNXI_GPC_SPI0);
break;
case 0x1689: /* Allwinner A64 */
gpio_set_cfgpin(dev, PC, 0, SUN50I_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 1, SUN50I_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 2, SUN50I_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0);
break;
case 0x1816: /* Allwinner V536 */
case 0x1817: /* Allwinner V831 */
gpio_set_cfgpin(dev, PC, 1, SUN50I_GPC_SPI0); /* SPI0-CS */
/* fall-through */
case 0x1728: /* Allwinner H6 */
gpio_set_cfgpin(dev, PC, 0, SUN50I_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 2, SUN50I_GPC_SPI0);
gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0);
/* PC5 is SPI0-CS on the H6, and SPI0-HOLD on the V831 */
gpio_set_cfgpin(dev, PC, 5, SUN50I_GPC_SPI0);
break;
case 0x1823: /* Allwinner H616 */
gpio_set_cfgpin(dev, PC, 0, SUN50I_GPC_SPI0); /* SPI0_CLK */
gpio_set_cfgpin(dev, PC, 2, SUN50I_GPC_SPI0); /* SPI0_MOSI */
gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0); /* SPI0_CS0 */
gpio_set_cfgpin(dev, PC, 4, SUN50I_GPC_SPI0); /* SPI0_MISO */
break;
default: /* Unknown/Unsupported SoC */
if (!soc_info->spi_base) {
printf("SPI support not implemented yet for %x (%s)!\n",
soc_info->soc_id, soc_info->name);
return false;
}

if (soc_is_h6_style(dev)) {
reg_val = readl(H6_CCM_SPI_BGR);
/* Setup SPI0 pins muxing */
gpio_set_cfgpin(dev, PC, spi_pin(soc_info, 1), soc_info->spi_pinmux);
gpio_set_cfgpin(dev, PC, spi_pin(soc_info, 2), soc_info->spi_pinmux);
gpio_set_cfgpin(dev, PC, spi_pin(soc_info, 3), soc_info->spi_pinmux);
gpio_set_cfgpin(dev, PC, spi_pin(soc_info, 4), soc_info->spi_pinmux);

ccu_base = dev->soc_info->ccu_base;
if (dev->soc_info->flags & H6_STYLE_CLOCKS) {
reg_val = readl(ccu_base + H6_CCM_SPI_BGR_OFF);
reg_val |= H6_CCM_SPI0_GATE_RESET;
writel(reg_val, H6_CCM_SPI_BGR);
writel(reg_val, ccu_base + H6_CCM_SPI_BGR_OFF);
} else {
if (spi_is_sun6i(dev)) {
/* Deassert SPI0 reset */
reg_val = readl(SUN6I_BUS_SOFT_RST_REG0);
reg_val = readl(ccu_base + SUN6I_BUS_SOFT_RST_REG0_OFF);
reg_val |= SUN6I_SPI0_RST;
writel(reg_val, SUN6I_BUS_SOFT_RST_REG0);
writel(reg_val, ccu_base + SUN6I_BUS_SOFT_RST_REG0_OFF);
}

reg_val = readl(CCM_AHB_GATING0);
reg_val = readl(ccu_base + CCM_AHB_GATING0_OFF);
reg_val |= CCM_AHB_GATE_SPI0;
writel(reg_val, CCM_AHB_GATING0);
writel(reg_val, ccu_base + CCM_AHB_GATING0_OFF);
}

if (soc_info->soc_id == 0x1663) { /* suniv F1C100s */
Expand All @@ -291,18 +221,20 @@ static bool spi0_init(feldev_handle *dev)
*/

/* Set PLL6 to 600MHz */
writel(0x80041801, SUNIV_PLL6_CTL);
writel(0x80041801, ccu_base + SUNIV_PLL6_CTL_OFF);
/* PLL6:AHB:APB = 6:2:1 */
writel(0x00003180, SUNIV_AHB_APB_CFG);
writel(0x00003180, ccu_base + SUNIV_AHB_APB_CFG_OFF);
/* divide by 32 */
writel(CCM_SPI0_CLK_DIV_BY_32, SUN6I_SPI0_CCTL);
} else {
/* divide 24MHz OSC by 4 */
writel(CCM_SPI0_CLK_DIV_BY_4,
spi_is_sun6i(dev) ? SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL);
/* Choose 24MHz from OSC24M and enable clock */
writel(1U << 31,
soc_is_h6_style(dev) ? H6_CCM_SPI0_CLK : CCM_SPI0_CLK);
if (dev->soc_info->flags & H6_STYLE_CLOCKS)
writel(1U << 31, ccu_base + H6_CCM_SPI0_CLK_OFF);
else
writel(1U << 31, ccu_base + CCM_SPI0_CLK_OFF);
}

if (spi_is_sun6i(dev)) {
Expand Down
4 changes: 2 additions & 2 deletions fel.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ void aw_fel_print_sid(feldev_handle *dev, bool force_workaround)
return;
}

if (soc_info->sid_fix || force_workaround) {
if (soc_info->flags & NEEDS_SID_FIX || force_workaround) {
pr_info("Read SID key via registers, base = 0x%08X\n",
soc_info->sid_base);
} else {
Expand Down Expand Up @@ -788,7 +788,7 @@ uint32_t aw_fel_write_and_execute_spl(feldev_handle *dev, uint8_t *buf, size_t l
if (spl_checksum != 0)
pr_fatal("SPL: checksum check failed\n");

if (soc_info->needs_l2en) {
if (soc_info->flags & NEEDS_L2EN) {
pr_info("Enabling the L2 cache\n");
aw_enable_l2_cache(dev, soc_info);
}
Expand Down
5 changes: 3 additions & 2 deletions fel_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ static void aw_disable_icache(feldev_handle *dev)

void aw_fel_write(feldev_handle *dev, const void *buf, uint32_t offset, size_t len)
{
if (dev->soc_info->icache_fix && !dev->usb->icache_hacked) {
if (dev->soc_info->flags & NEEDS_ICACHE_FIX &&
!dev->usb->icache_hacked) {
aw_disable_icache(dev);
dev->usb->icache_hacked = true;
}
Expand Down Expand Up @@ -617,7 +618,7 @@ int fel_read_sid(feldev_handle *dev, uint32_t *result,
if ((offset & 3) || (length & 3)) /* needs to be 32-bit aligned */
return -3;

if (soc->sid_fix || force_workaround)
if (soc->flags & NEEDS_SID_FIX || force_workaround)
/* Work around SID issues by using ARM thunk code */
fel_get_sid_registers(dev, result, offset, length);
else
Expand Down
Loading