diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-bsp')
31 files changed, 6221 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch new file mode 100644 index 000000000..73ab78a65 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch @@ -0,0 +1,424 @@ +Index: u-boot/arch/arm/mach-aspeed/flash.c +=================================================================== +--- u-boot.orig/arch/arm/mach-aspeed/flash.c ++++ u-boot/arch/arm/mach-aspeed/flash.c +@@ -28,6 +28,7 @@ + #include <common.h> + #include <asm/processor.h> + #include <asm/byteorder.h> ++#include <asm/io.h> + #include <environment.h> + + #include <asm/arch/ast_scu.h> +@@ -199,7 +200,7 @@ static void reset_flash (flash_info_t * + if (info->dualport) + ulCtrlData |= 0x08; + #endif +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } + +@@ -228,28 +229,22 @@ static void enable_write (flash_info_t * + + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x06); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x06, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x05); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x05, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (!(jReg & 0x02)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } + +@@ -280,30 +275,23 @@ static void write_status_register (flash + + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x01); +- udelay(10); +- *(uchar *) (base) = (uchar) (data); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x01, base); ++ writeb(data, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x05); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x05, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (jReg & 0x01); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + } + + static void enable4b (flash_info_t * info) +@@ -330,13 +318,11 @@ static void enable4b (flash_info_t * inf + + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0xb7); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0xb7, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } /* enable4b */ + +@@ -366,29 +352,23 @@ static void enable4b_spansion (flash_inf + /* Enable 4B: BAR0 D[7] = 1 */ + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x17); +- udelay(10); +- *(uchar *) (base) = (uchar) (0x80); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x17, base); ++ writeb(0x80, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x16); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x16, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (!(jReg & 0x80)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } /* enable4b_spansion */ + +@@ -420,14 +400,11 @@ static void enable4b_numonyx (flash_info + /* Enable 4B: CMD:0xB7 */ + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0xB7); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0xB7, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } /* enable4b_numonyx */ + +@@ -463,63 +440,49 @@ static void flash_write_buffer (flash_in + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x02); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x02, base); + if (info->address32) + { +- *(uchar *) (base) = (uchar) ((offset & 0xff000000) >> 24); +- udelay(10); ++ writeb((uchar) ((offset & 0xff000000) >> 24), base); + } +- *(uchar *) (base) = (uchar) ((offset & 0xff0000) >> 16); +- udelay(10); +- *(uchar *) (base) = (uchar) ((offset & 0x00ff00) >> 8); +- udelay(10); +- *(uchar *) (base) = (uchar) ((offset & 0x0000ff)); +- udelay(10); ++ writeb((uchar) ((offset & 0xff0000) >> 16), base); ++ writeb((uchar) ((offset & 0x00ff00) >> 8), base); ++ writeb((uchar) ((offset & 0x0000ff)), base); + + for (j=0; j<len; j++) + { +- *(uchar *) (base) = *(uchar *) (src++); +- udelay(10); ++ writeb(*src++, base); + } + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x05); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x05, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while ((jReg & 0x01)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + /* RFSR */ + if (info->specificspi == SpecificSPI_N25Q512) + { + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x70); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x70, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (!(jReg & 0x80)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + } + } + +@@ -603,57 +566,44 @@ int flash_erase (flash_info_t * info, in + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0xd8); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0xd8, base); + if (info->address32) + { +- *(uchar *) (base) = (uchar) ((offset & 0xff000000) >> 24); +- udelay(10); ++ writeb((uchar) ((offset & 0xff000000) >> 24), base); + } +- *(uchar *) (base) = (uchar) ((offset & 0xff0000) >> 16); +- udelay(10); +- *(uchar *) (base) = (uchar) ((offset & 0x00ff00) >> 8); +- udelay(10); +- *(uchar *) (base) = (uchar) ((offset & 0x0000ff)); +- udelay(10); ++ writeb((uchar) ((offset & 0xff0000) >> 16), base); ++ writeb((uchar) ((offset & 0x00ff00) >> 8), base); ++ writeb((uchar) ((offset & 0x0000ff)), base); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x05); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x05, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while ((jReg & 0x01)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + /* RFSR */ + if (info->specificspi == SpecificSPI_N25Q512) + { + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x70); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x70, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (!(jReg & 0x80)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + } + + putc ('.'); +@@ -764,22 +714,16 @@ static ulong flash_get_size (ulong base, + } + + /* Get Flash ID */ +- ulCtrlData = *(ulong *) (info->reg_base + CtrlOffset) & CMD_MASK; ++ ulCtrlData = readl(info->reg_base + CtrlOffset) & CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (vbase) = (uchar) (0x9F); +- udelay(10); +- ch[0] = *(volatile uchar *)(vbase); +- udelay(10); +- ch[1] = *(volatile uchar *)(vbase); +- udelay(10); +- ch[2] = *(volatile uchar *)(vbase); +- udelay(10); +- ulCtrlData = *(ulong *) (info->reg_base + CtrlOffset) & CMD_MASK; ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x9F, vbase); ++ ch[0] = readb(vbase); ++ ch[1] = readb(vbase); ++ ch[2] = readb(vbase); ++ ulCtrlData = readl(info->reg_base + CtrlOffset) & CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + ulID = ((ulong)ch[0]) | ((ulong)ch[1] << 8) | ((ulong)ch[2] << 16) ; + info->flash_id = ulID; + +@@ -1294,13 +1238,13 @@ static ulong flash_get_size (ulong base, + + if (info->address32) { + #ifndef AST_SOC_G5 +- reg = *((volatile ulong*) 0x1e6e2070); /* set H/W Trappings */ ++ reg = readl(0x1e6e2070); /* set H/W Trappings */ + reg |= 0x10; +- *((volatile ulong*) 0x1e6e2070) = reg; ++ writel(reg, 0x1e6e2070); + #endif +- reg = *((volatile ulong*) (info->reg_base + 0x4)); /* enable 32b control bit*/ ++ reg = readl(info->reg_base + 0x4); /* enable 32b control bit*/ + reg |= (0x01 << info->CE); +- *((volatile ulong*) (info->reg_base + 0x4)) = reg; ++ writel(reg, info->reg_base + 0x4); + + /* set flash chips to 32bits addressing mode */ + if ((info->flash_id & 0xFF) == 0x01) /* Spansion */ +@@ -1322,7 +1266,7 @@ unsigned long flash_init (void) + unsigned long size = 0; + int i; + +- *((volatile ulong*) AST_FMC_BASE) |= 0x800f0000; /* enable Flash Write */ ++ writel(readl(AST_FMC_BASE) | 0x800f0000, AST_FMC_BASE); /* enable Flash Write */ + + /* Init: FMC */ + /* BANK 0 : FMC CS0 , 1: FMC CS1, */ +@@ -1352,7 +1296,7 @@ unsigned long flash_init (void) + #ifdef CONFIG_SPI0_CS + //pin switch by trap[13:12] -- [0:1] Enable SPI Master + ast_scu_spi_master(1); /* enable SPI master */ +- *((volatile ulong*) AST_FMC_SPI0_BASE) |= 0x10000; /* enable Flash Write */ ++ writel(readl(AST_FMC_SPI0_BASE) | 0x10000, AST_FMC_SPI0_BASE); /* enable Flash Write */ + flash_info[CONFIG_FMC_CS].sysspi = 1; + flash_info[CONFIG_FMC_CS].reg_base = AST_FMC_SPI0_BASE; + flash_info[CONFIG_FMC_CS].flash_id = FLASH_UNKNOWN; +@@ -1403,21 +1347,24 @@ void memmove_dma(void * dest,const void + poll_time = 100; /* set 100 us as default */ + + /* force end of burst read */ +- *(volatile ulong *) (AST_FMC_BASE + CS0_CTRL) |= CE_HIGH; +- *(volatile ulong *) (AST_FMC_BASE + CS0_CTRL) &= ~CE_HIGH; +- +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_CONTROL) = (ulong) (~FLASH_DMA_ENABLE); +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_FLASH_BASE) = (ulong) (src); +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_DRAM_BASE) = (ulong) (dest); +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_LENGTH) = (ulong) (count_align); +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_CONTROL) = (ulong) (FLASH_DMA_ENABLE); ++ data = readl(AST_FMC_BASE + CS0_CTRL); ++ writel(data | CE_HIGH, AST_FMC_BASE + CS0_CTRL); ++ writel(data & ~CE_HIGH, AST_FMC_BASE + CS0_CTRL); ++ ++ writel(~FLASH_DMA_ENABLE, AST_FMC_BASE + REG_FLASH_DMA_CONTROL); ++ writel((ulong)src, AST_FMC_BASE + REG_FLASH_DMA_FLASH_BASE); ++ writel((ulong)dest, AST_FMC_BASE + REG_FLASH_DMA_DRAM_BASE); ++ writel(count_align, AST_FMC_BASE + REG_FLASH_DMA_LENGTH); ++ writel(FLASH_DMA_ENABLE, AST_FMC_BASE + REG_FLASH_DMA_CONTROL); + + /* wait poll */ + do { + udelay(poll_time); +- data = *(ulong *) (AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS); ++ data = readl(AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS); + } while (!(data & FLASH_STATUS_DMA_READY)); + + /* clear status */ +- *(ulong *) (AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS) |= FLASH_STATUS_DMA_CLEAR; ++ data = readl(AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS); ++ writel(data | FLASH_STATUS_DMA_CLEAR, ++ AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS); + } diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch new file mode 100644 index 000000000..86fa5b7d5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch @@ -0,0 +1,42 @@ +Index: u-boot/include/configs/ast-common.h +=================================================================== +--- u-boot.orig/include/configs/ast-common.h ++++ u-boot/include/configs/ast-common.h +@@ -103,10 +103,13 @@ + #define CONFIG_SYS_MAX_FLASH_BANKS (CONFIG_FMC_CS) + #define CONFIG_SYS_MAX_FLASH_SECT (8192) /* max number of sectors on one chip */ + #define CONFIG_ENV_IS_IN_FLASH 1 +-#define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + 0x60000) ++#define CONFIG_ENV_OFFSET 0x2400000 /* environment starts here */ ++#define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET) ++#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ + +-#define CONFIG_ENV_OFFSET 0x60000 /* environment starts here */ +-#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ ++#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) ++#define CONFIG_ENV_ADDR_REDUND (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET_REDUND) ++#define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE + + #define CONFIG_BOOTCOMMAND "bootm 20080000" + #define CONFIG_ENV_OVERWRITE +Index: u-boot/common/board_r.c +=================================================================== +--- u-boot.orig/common/board_r.c ++++ u-boot/common/board_r.c +@@ -494,10 +494,14 @@ static int should_load_env(void) + static int initr_env(void) + { + /* initialize environment */ +- if (should_load_env()) ++ if (should_load_env()) { ++ /* try again, in case the environment failed to load the first time */ ++ if (!gd->env_valid) ++ env_init(); + env_relocate(); +- else ++ } else { + set_default_env(NULL); ++ } + #ifdef CONFIG_OF_CONTROL + setenv_addr("fdtcontroladdr", gd->fdt_blob); + #endif diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch new file mode 100644 index 000000000..8bc0a3ed3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch @@ -0,0 +1,75 @@ +From 2f0e14630abec2c9679d21901072648c7802f2c4 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Tue, 11 Sep 2018 16:24:06 +0800 +Subject: [PATCH] Make sure debug uart is using 24MHz clock source + +u-boot defines the uart5(debug console) as 24MHz, +set the SCU14[28] to 0, to make sure the clock source is 24M + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + arch/arm/include/asm/arch-aspeed/ast_scu.h | 2 ++ + arch/arm/include/asm/arch-aspeed/platform.h | 1 + + arch/arm/mach-aspeed/ast-scu.c | 6 ++++++ + board/aspeed/ast-g5/ast-g5.c | 8 ++++++++ + 4 files changed, 17 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h +index d248416..98e6335 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h ++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h +@@ -45,4 +45,6 @@ extern void ast_scu_init_eth(u8 num); + extern void ast_scu_multi_func_eth(u8 num); + extern void ast_scu_multi_func_romcs(u8 num); + ++void ast_config_uart5_clk(void); ++ + #endif +diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h +index c9c7a81..a423052 100644 +--- a/arch/arm/include/asm/arch-aspeed/platform.h ++++ b/arch/arm/include/asm/arch-aspeed/platform.h +@@ -27,6 +27,7 @@ + #include <asm/arch/ast2400_platform.h> + #elif defined(AST_SOC_G5) + #include <asm/arch/ast_g5_platform.h> ++#define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */ + #else + #err "No define for platform.h" + #endif +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index 0cc0d67..902263b 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -496,3 +496,9 @@ void ast_scu_get_who_init_dram(void) + break; + } + } ++ ++void ast_config_uart5_clk(void) ++{ ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) & ++ ~(1 << 28), AST_SCU_MISC2_CTRL); ++} +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index e67a4bf..5a1fade 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -16,6 +16,14 @@ + + DECLARE_GLOBAL_DATA_PTR; + ++int board_early_init_f(void) ++{ ++ /* make sure uart5 is using 24MHz clock */ ++ ast_config_uart5_clk(); ++ ++ return 0; ++} ++ + int board_init(void) + { + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch new file mode 100644 index 000000000..0385a5e31 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch @@ -0,0 +1,56 @@ +From b344cf4462acb1f043ed903ccee713e24ce7226d Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Wed, 7 Nov 2018 13:57:57 +0800 +Subject: [PATCH 1/1] enable passthrough in uboot + +--- + arch/arm/mach-aspeed/ast-scu.c | 22 ++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5.c | 2 ++ + 2 files changed, 24 insertions(+) + +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index 902263b28b..c83931ed54 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -502,3 +502,25 @@ void ast_config_uart5_clk(void) + ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) & + ~(1 << 28), AST_SCU_MISC2_CTRL); + } ++ ++ ++void ast_enable_pass_through(void) ++{ ++ //Enable GPIOE pin mode, SCU80[16:23] = 00 */ ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & (~0x00FF0000), ++ AST_SCU_FUN_PIN_CTRL1); ++ ++ //Enable all pass through pins by setting SCU8C[15:12] = 0x3. ++ //Pass-through pins set: ++ //GPIOE0 -> GPIOE1 ++ //GPIOE2 -> GPIOE3 ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL4) | (0x3000), ++ AST_SCU_FUN_PIN_CTRL4); ++ ++ //Disable HWStrap for GPIOE pass-through mode ++ //The write operation to SCU70(0x1e6e2070) only can set to '1'. ++ //To clear to '0', it must write '1' to 0x1e6e207c ++ if (ast_scu_read(AST_SCU_HW_STRAP1) & (0x1 << 22)){ ++ ast_scu_write((0x1 << 22), AST_SCU_REVISION_ID); ++ } ++} +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index 5a1fadeedd..b492003f51 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -20,6 +20,8 @@ int board_early_init_f(void) + { + /* make sure uart5 is using 24MHz clock */ + ast_config_uart5_clk(); ++ /*enable pass through*/ ++ ast_enable_pass_through(); + + return 0; + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch new file mode 100644 index 000000000..dbaf7b362 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch @@ -0,0 +1,389 @@ +From f33755167ddcdebbf56bc875e4091990273c6997 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 10:21:40 -0800 +Subject: [PATCH 1/7] Add Aspeed g5 interrupt support + +This adds a few new files to the board g5 directory. Several Intel +features require interrupts running in U-Boot, so this adds basic +interrupt registration and handling support. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Change-Id: Id7072f1408dcf364968b1b74f2192e50a22a82f0 +--- + Kconfig | 13 ++ + arch/arm/lib/interrupts.c | 11 ++ + board/aspeed/ast-g5/Makefile | 4 +- + board/aspeed/ast-g5/ast-g5-irq.c | 176 ++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-irq.h | 39 ++++++ + board/aspeed/ast-g5/ast-g5.c | 3 + + board/aspeed/ast-g5/ast-g5.h | 7 ++ + cmd/Kconfig | 5 + + configs/ast_g5_ncsi_2boot_defconfig | 1 + + configs/ast_g5_ncsi_defconfig | 1 + + configs/ast_g5_phy_defconfig | 1 + + 11 files changed, 260 insertions(+), 1 deletion(-) + create mode 100644 board/aspeed/ast-g5/ast-g5-irq.c + create mode 100644 board/aspeed/ast-g5/ast-g5-irq.h + create mode 100644 board/aspeed/ast-g5/ast-g5.h + +diff --git a/Kconfig b/Kconfig +index 3ceff25032..d6439d01ca 100644 +--- a/Kconfig ++++ b/Kconfig +@@ -115,6 +115,19 @@ if EXPERT + When disabling this, please check if malloc calls, maybe + should be replaced by calloc - if one expects zeroed memory. + endif ++ ++config USE_IRQ ++ bool "Use interrupts" ++ default n ++ ++config STACKSIZE_IRQ ++ int "Size for IRQ stack (only if USE_IRQ enabled)" ++ default 16384 ++ ++config STACKSIZE_FIQ ++ int "Size for FIQ stack (only if USE_IRQ enabled)" ++ default 16384 ++ + endmenu # General setup + + menu "Boot images" +diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c +index ed83043abb..a96b3aa070 100644 +--- a/arch/arm/lib/interrupts.c ++++ b/arch/arm/lib/interrupts.c +@@ -94,6 +94,17 @@ int disable_interrupts (void) + : "memory"); + return (old & 0x80) == 0; + } ++ ++int global_interrupts_enabled(void) ++{ ++ unsigned long old; ++ __asm__ __volatile__("mrs %0, cpsr\n" ++ : "=r" (old) ++ : ++ : "memory"); ++ return (old & 0x80) == 0; ++} ++ + #else + int interrupt_init (void) + { +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index d1d7f8525e..d41b11589f 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -1 +1,2 @@ +-obj-y = ast-g5.o ++obj-y += ast-g5.o ++obj-y += ast-g5-irq.o +diff --git a/board/aspeed/ast-g5/ast-g5-irq.c b/board/aspeed/ast-g5/ast-g5-irq.c +new file mode 100644 +index 0000000000..860f16cf05 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-irq.c +@@ -0,0 +1,176 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * 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; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++#include <netdev.h> ++ ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/ast-sdmc.h> ++#include <asm/io.h> ++ ++#include "ast-g5.h" ++#include "ast-g5-irq.h" ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#ifdef CONFIG_USE_IRQ ++ ++#define VIC_STATUS_L 0x80 ++#define VIC_STATUS_H 0x84 ++#define VIC_IRQ_SELECTION_L 0x98 ++#define VIC_IRQ_SELECTION_H 0x9C ++#define VIC_ENABLE_L 0xA0 ++#define VIC_ENABLE_H 0xA4 ++#define VIC_ENABLE_CLEAR_L 0xA8 ++#define VIC_ENABLE_CLEAR_H 0xAC ++#define VIC_INTERRUPT_CLEAR_L 0xD8 ++#define VIC_INTERRUPT_CLEAR_H 0xDC ++ ++#define VIC_CLEAR_ALL (~0) ++ ++int arch_interrupt_init_early(void) ++{ ++ writel(VIC_CLEAR_ALL, AST_VIC_BASE + VIC_ENABLE_CLEAR_L); ++ writel(VIC_CLEAR_ALL, AST_VIC_BASE + VIC_ENABLE_CLEAR_H); ++ return 0; ++} ++int arch_interrupt_init(void) ++{ ++ return 0; ++} ++ ++#define AST_IRQ_START_L 0 ++#define AST_IRQ_END_L 31 ++#define AST_IRQ_START_H 32 ++#define AST_IRQ_END_H 63 ++#define AST_IRQ_COUNT 64 ++static interrupt_handler_t *handlers[AST_IRQ_COUNT] = {NULL}; ++static unsigned long irq_total = 0; ++static unsigned long irq_counts[AST_IRQ_COUNT] = {0}; ++ ++int request_irq(int irq, interrupt_handler_t *handler) ++{ ++ if (irq < AST_IRQ_START_L || irq > AST_IRQ_END_H) { ++ printf("irq %d out of range\n", irq); ++ return -1; ++ } ++ if (handlers[irq]) { ++ printf("irq %d already in use (%p)\n", irq, handlers[irq]); ++ return -1; ++ } ++ handlers[irq] = handler; ++ if (irq < AST_IRQ_START_H) { ++ writel((1 << irq), AST_VIC_BASE + VIC_ENABLE_L); ++ } else { ++ writel((1 << (irq - AST_IRQ_START_H)), ++ AST_VIC_BASE + VIC_ENABLE_H); ++ } ++ return 0; ++} ++ ++int release_irq(int irq) ++{ ++ if (irq < AST_IRQ_START_L || irq > AST_IRQ_END_H) { ++ return -1; ++ } ++ if (handlers[irq]) { ++ handlers[irq] = NULL; ++ if (irq < AST_IRQ_START_H) { ++ writel((1 << irq), AST_VIC_BASE + VIC_ENABLE_CLEAR_L); ++ } else { ++ writel((1 << (irq - AST_IRQ_START_H)), ++ AST_VIC_BASE + VIC_ENABLE_CLEAR_H); ++ } ++ } ++ return 0; ++} ++ ++extern int global_interrupts_enabled(void); ++int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ int i; ++ int enabled = global_interrupts_enabled(); ++ unsigned long long irqs_enabled = ++ ((unsigned long long)readl(AST_VIC_BASE + VIC_ENABLE_H)) ++ << AST_IRQ_START_H ++ | readl(AST_VIC_BASE + VIC_ENABLE_L); ++ printf("interrupts %sabled\n", (enabled ? "en" : "dis")); ++ for (i = AST_IRQ_START_L; i < AST_IRQ_COUNT; i++) { ++ printf("% 2i (% 3s): %lu\n", i, ++ ((irqs_enabled & 1) ? "on" : "off"), irq_counts[i]); ++ irqs_enabled >>= 1; ++ } ++ printf("total: %lu\n", irq_total); ++ return 0; ++} ++ ++void do_irq(struct pt_regs *pt_regs) ++{ ++ uint32_t irq = readl(AST_VIC_BASE + VIC_STATUS_L); ++ int i; ++ irq_total++; ++ if (irq) { ++ // handler irq0-31 ++ for (i = AST_IRQ_START_L; i <= AST_IRQ_END_L; i++) { ++ if (irq & (1 << i)) { ++ irq_counts[i]++; ++ /* mask */ ++ writel((1 << i), ++ AST_VIC_BASE + VIC_ENABLE_CLEAR_L); ++ if (handlers[i]) { ++ handlers[i](pt_regs); ++ /* clear */ ++ writel((1 << i), ++ AST_VIC_BASE ++ + VIC_INTERRUPT_CLEAR_L); ++ /* unmask */ ++ writel((1 << i), ++ AST_VIC_BASE + VIC_ENABLE_L); ++ } else { ++ printf("unexpected interrupt %i; masking\n", ++ i); ++ /* clear; do not unmask */ ++ writel((1 << i), ++ AST_VIC_BASE ++ + VIC_INTERRUPT_CLEAR_L); ++ } ++ } ++ } ++ } ++ irq = readl(AST_VIC_BASE + VIC_STATUS_H); ++ if (irq) { ++ // handler irq32-63 ++ for (i = AST_IRQ_START_H; i <= AST_IRQ_END_H; i++) { ++ if (irq & (1 << (i - AST_IRQ_START_H))) { ++ irq_counts[i]++; ++ /* mask */ ++ writel((1 << (i - AST_IRQ_START_H)), ++ AST_VIC_BASE + VIC_ENABLE_CLEAR_H); ++ if (handlers[i]) { ++ handlers[i](pt_regs); ++ /* clear */ ++ writel((1 << (i - AST_IRQ_START_H)), ++ AST_VIC_BASE ++ + VIC_INTERRUPT_CLEAR_H); ++ /* unmask */ ++ writel((1 << (i - AST_IRQ_START_H)), ++ AST_VIC_BASE + VIC_ENABLE_H); ++ } else { ++ printf("unexpected interrupt %i; masking\n", ++ i); ++ /* clear; do not unmask */ ++ writel((1 << (i - AST_IRQ_START_H)), ++ AST_VIC_BASE ++ + VIC_INTERRUPT_CLEAR_H); ++ } ++ } ++ } ++ } ++} ++#endif +diff --git a/board/aspeed/ast-g5/ast-g5-irq.h b/board/aspeed/ast-g5/ast-g5-irq.h +new file mode 100644 +index 0000000000..703eeabf13 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-irq.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * 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; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#ifndef __AST_G5_IRQ_H__ ++#define __AST_G5_IRQ_H__ ++ ++#include <common.h> ++ ++#ifdef CONFIG_USE_IRQ ++ ++int arch_interrupt_init_early(void); ++ ++int request_irq(int irq, interrupt_handler_t *handler); ++ ++int release_irq(int irq); ++ ++#else /* CONFIG_USE_IRQ */ ++ ++int arch_interrupt_init_early(void) { ++ return 0; ++} ++ ++int request_irq(int irq, interrupt_handler_t *handler) { ++ return -1; ++} ++ ++int release_irq(int irq) { ++ return -1; ++} ++ ++#endif /* CONFIG_USE_IRQ */ ++ ++#endif /* __AST_G5_IRQ_H__ */ +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index b492003f51..2472aa3603 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -14,6 +14,8 @@ + #include <asm/arch/ast-sdmc.h> + #include <asm/io.h> + ++#include "ast-g5.h" ++ + DECLARE_GLOBAL_DATA_PTR; + + int board_early_init_f(void) +@@ -22,6 +24,7 @@ int board_early_init_f(void) + ast_config_uart5_clk(); + /*enable pass through*/ + ast_enable_pass_through(); ++ arch_interrupt_init_early(); + + return 0; + } +diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h +new file mode 100644 +index 0000000000..9fd10eccb3 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5.h +@@ -0,0 +1,7 @@ ++#ifndef _AST_G5_H_ ++#define _AST_G5_H_ ++ ++#include <common.h> ++#include "ast-g5-irq.h" ++ ++#endif /* _AST_G5_H_ */ +diff --git a/cmd/Kconfig b/cmd/Kconfig +index d69b817c82..33be2407d2 100644 +--- a/cmd/Kconfig ++++ b/cmd/Kconfig +@@ -313,6 +313,11 @@ endmenu + + menu "Device access commands" + ++config CMD_IRQ ++ bool "interrupts - enable/disable interrupts" ++ depends on USE_IRQ ++ default y ++ + config CMD_DM + bool "dm - Access to driver model information" + depends on DM +diff --git a/configs/ast_g5_ncsi_2boot_defconfig b/configs/ast_g5_ncsi_2boot_defconfig +index 2d28c86966..d5b7894a9e 100644 +--- a/configs/ast_g5_ncsi_2boot_defconfig ++++ b/configs/ast_g5_ncsi_2boot_defconfig +@@ -33,3 +33,4 @@ CONFIG_CMD_CRC32=y + CONFIG_LOOPW=y + CONFIG_CMD_MEMTEST=y + CONFIG_CMD_MX_CYCLIC=y ++CONFIG_USE_IRQ=y +diff --git a/configs/ast_g5_ncsi_defconfig b/configs/ast_g5_ncsi_defconfig +index 74029ed514..9481e5fb6e 100644 +--- a/configs/ast_g5_ncsi_defconfig ++++ b/configs/ast_g5_ncsi_defconfig +@@ -11,3 +11,4 @@ CONFIG_HUSH_PARSER=y + CONFIG_OF_LIBFDT=y + CONFIG_SPI_FLASH=y + CONFIG_SYS_NS16550=y ++CONFIG_USE_IRQ=y +diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig +index 767f3af605..4aefcf49e8 100644 +--- a/configs/ast_g5_phy_defconfig ++++ b/configs/ast_g5_phy_defconfig +@@ -12,3 +12,4 @@ CONFIG_HUSH_PARSER=y + CONFIG_OF_LIBFDT=y + CONFIG_SPI_FLASH=y + CONFIG_SYS_NS16550=y ++CONFIG_USE_IRQ=y +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch new file mode 100644 index 000000000..18cc2f9c8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch @@ -0,0 +1,330 @@ +From 7ad0ea13337550f35c1e726f21d4751bf74078d6 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 10:21:40 -0800 +Subject: [PATCH 2/7] Add espi support + +This adds basic eSPI support for U-Boot. The eSPI driver works best with +interrupts because the timing of the initialization with the PCH is not +trivial. + +The espi driver is currently just a bare-minimum driver allowing the +host to boot. In the future it may be expanded to have further +functions. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Change-Id: Id7072f1408dcf364968b1b74f2192e50a22a82f0 +--- + arch/arm/include/asm/arch-aspeed/regs-scu.h | 2 + + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-espi.c | 231 ++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-intel.c | 16 ++ + board/aspeed/ast-g5/ast-g5.c | 3 + + 5 files changed, 253 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-espi.c + create mode 100644 board/aspeed/ast-g5/ast-g5-intel.c + +diff --git a/arch/arm/include/asm/arch-aspeed/regs-scu.h b/arch/arm/include/asm/arch-aspeed/regs-scu.h +index b714fa9234..10b983a966 100644 +--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h ++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h +@@ -552,6 +552,8 @@ + + #define CLK_25M_IN (0x1 << 23) + ++#define SCU_HW_STRAP_FAST_RESET (1 << 27) ++#define SCU_HW_STRAP_ESPI_ENABLED (1 << 25) + #define SCU_HW_STRAP_2ND_BOOT_WDT (0x1 << 17) + #define SCU_HW_STRAP_SUPER_IO_CONFIG (0x1 << 16) + #define SCU_HW_STRAP_VGA_CLASS_CODE (0x1 << 15) +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index d41b11589f..58e0c648f4 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -1,2 +1,4 @@ + obj-y += ast-g5.o ++obj-y += ast-g5-intel.o ++obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o +diff --git a/board/aspeed/ast-g5/ast-g5-espi.c b/board/aspeed/ast-g5/ast-g5-espi.c +new file mode 100644 +index 0000000000..79ef253b86 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-espi.c +@@ -0,0 +1,231 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * 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; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++#include <asm/io.h> ++#include <asm/arch/regs-scu.h> ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/aspeed.h> ++ ++#include "ast-g5.h" ++ ++#define DEBUG_ESPI_ENABLED 1 ++#ifdef DEBUG_ESPI_ENABLED ++#define DBG_ESPI debug ++#else ++#define DBG_ESPI(...) ++#endif ++/* eSPI controller registers */ ++#define ESPI000 0x000 /* Engine Control. */ ++#define ESPI004 0x004 /* Engine Status. */ ++#define ESPI008 0x008 /* Interrupt Status. */ ++#define ESPI00C 0x00C /* Interrupt Enable. */ ++#define ESPI010 0x010 /* DMA Addr of Peripheral Channel Posted Rx pkt */ ++#define ESPI014 0x014 /* Control of Peripheral Channel Posted Rx pkt. */ ++#define ESPI018 0x018 /* Data port of Peripheral Channel Posted Rx pkt. */ ++#define ESPI020 0x020 /* DMA Addr of Peripheral Channel Posted Tx pkt. */ ++#define ESPI024 0x024 /* Control of Peripheral Channel Posted Tx pkt. */ ++#define ESPI028 0x028 /* Data port of Peripheral Channel Posted Tx pkt. */ ++#define ESPI030 0x030 /* DMA Addr of Peripheral Channel Non-Posted Tx pkt. */ ++#define ESPI034 0x034 /* Control of Peripheral Channel Non-Posted Tx pkt. */ ++#define ESPI038 0x038 /* Data port of Peripheral Channel Non-Posted Tx pkt. */ ++#define ESPI040 0x040 /* DMA Addr of OOB Channel Rx pkt. */ ++#define ESPI044 0x044 /* Control of OOB Channel Rx pkt. */ ++#define ESPI048 0x048 /* Data port of OOB Channel Rx pkt. */ ++#define ESPI050 0x050 /* DMA Addr of OOB Channel Tx pkt. */ ++#define ESPI054 0x054 /* Control of OOB Channel Tx pkt. */ ++#define ESPI058 0x058 /* Data port of OOB Channel Tx pkt. */ ++#define ESPI060 0x060 /* DMA Addr of Flash Channel Rx pkt. */ ++#define ESPI064 0x064 /* Control of Flash Channel Rx pkt. */ ++#define ESPI068 0x068 /* Data port of Flash Channel Rx pkt. */ ++#define ESPI070 0x070 /* DMA Addr of Flash Channel Tx pkt. */ ++#define ESPI074 0x074 /* Control of Flash Channel Tx pkt. */ ++#define ESPI078 0x078 /* Data port of Flash Channel Tx pkt. */ ++#define ESPI084 0x084 /* Mapping Src Addr of Peripheral Channel Rx pkt. */ ++#define ESPI088 0x088 /* Mapping Tgt Addr of Peripheral Channel Rx pkt. */ ++#define ESPI08C 0x08C /* Mapping Addr Mask of Peripheral Channel Rx pkt. */ ++#define ESPI090 0x090 /* Mapping Target Addr and Mask of Flash Channel. */ ++#define ESPI094 0x094 /* Interrupt enable of System Event from Master. */ ++#define ESPI098 0x098 /* System Event from and to Master. */ ++#define ESPI09C 0x09C /* GPIO through Virtual Wire Channel. */ ++#define ESPI0A0 0x0A0 /* General Capabilities and Configurations. */ ++#define ESPI0A4 0x0A4 /* Channel 0 Capabilities and Configurations. */ ++#define ESPI0A8 0x0A8 /* Channel 1 Capabilities and Configurations. */ ++#define ESPI0AC 0x0AC /* Channel 2 Capabilities and Configurations. */ ++#define ESPI0B0 0x0B0 /* Channel 3 Capabilities and Configurations. */ ++#define ESPI0B4 0x0B4 /* GPIO Direction of Virtual Wire Channel. */ ++#define ESPI0B8 0x0B8 /* GPIO Selection of Virtual Wire Channel. */ ++#define ESPI0BC 0x0BC /* GPIO Reset Selection of Virtual Wire Channel. */ ++#define ESPI100 0x100 /* Interrupt enable of System Event 1 from Master. */ ++#define ESPI104 0x104 /* System Event 1 from and to Master. */ ++#define ESPI110 0x110 /* Interrupt type 0 of System Event from Master. */ ++#define ESPI114 0x114 /* Interrupt type 1 of System Event from Master. */ ++#define ESPI118 0x118 /* Interrupt type 2 of System Event from Master. */ ++#define ESPI11C 0x11C /* Interrupt status of System Event from Master. */ ++#define ESPI120 0x120 /* Interrupt type 0 of System Event 1 from Master. */ ++#define ESPI124 0x124 /* Interrupt type 1 of System Event 1 from Master. */ ++#define ESPI128 0x128 /* Interrupt type 2 of System Event 1 from Master. */ ++#define ESPI12C 0x12C /* Interrupt status of System Event 1 from Master. */ ++#define ESPICFG004 0x004 /* Device Identification. */ ++#define ESPICFG008 0x008 /* General Capabilities and Configurations. */ ++#define ESPICFG010 0x010 /* Channel 0 Capabilities and Configurations. */ ++#define ESPICFG020 0x020 /* Channel 1 Capabilities and Configurations. */ ++#define ESPICFG030 0x030 /* Channel 2 Capabilities and Configurations. */ ++#define ESPICFG040 0x040 /* Channel 3 Capabilities and Configurations. */ ++#define ESPICFG044 0x044 /* Channel 3 Capabilities and Configurations 2. */ ++#define ESPICFG800 0x800 /* GPIO Direction of Virtual Wire Channel. */ ++#define ESPICFG804 0x804 /* GPIO Selection of Virtual Wire Channel. */ ++#define ESPICFG808 0x808 /* GPIO Reset Selection of Virtual Wire Channel. */ ++#define ESPICFG810 0x810 /* Mapping Src Addr of Peripheral Channel Rx pkt */ ++#define ESPICFG814 0x814 /* Mapping Tgt Addr of Peripheral Channel Rx pkt */ ++#define ESPICFG818 0x818 /* Mapping Addr Mask of Peripheral Channel Rx pkt */ ++ ++/* ESPI000 bits */ ++#define AST_ESPI_OOB_CHRDY (1 << 4) ++#define AST_ESPI_FLASH_SW_CHRDY (0x1 << 7) ++#define AST_ESPI_FLASH_SW_READ (0x1 << 10) ++ ++/* ESPI00C bits (Interrupt Enable) */ ++#define AST_ESPI_IEN_SYS_EV (1 << 8) ++#define AST_ESPI_IEN_GPIO_EV (1 << 9) ++ ++/* ESPI008 bits ISR */ ++#define AST_ESPI_VW_SYS_EVT (1 << 8) ++#define AST_ESPI_VW_SYS_EV1 (1 << 22) ++ ++/* ESPI098 and ESPI11C bits */ ++#define AST_ESPI_OOB_RST_WARN (1 << 6) ++#define AST_ESPI_HOST_RST_WARN (1 << 8) ++#define AST_ESPI_OOB_RST_ACK (1 << 16) ++#define AST_ESPI_SL_BT_DONE (1 << 20) ++#define AST_ESPI_SL_BT_STATUS (1 << 23) ++#define AST_ESPI_HOST_RST_ACK (1 << 27) ++ ++/* ESPI104 bits */ ++#define AST_ESPI_SUS_WARN (1 << 0) ++#define AST_ESPI_SUS_ACK (1 << 20) ++ ++/* LPC chip ID */ ++#define SCR0SIO 0x170 ++#define IRQ_SRC_ESPI 23 /* IRQ 23 */ ++ ++static int espi_irq_handler(struct pt_regs *regs) ++{ ++ uint32_t irq_status = readl(AST_ESPI_BASE + ESPI008); ++ ++ DBG_ESPI("ISR irq_status : 0x%08X\n", irq_status); ++ ++ if (irq_status & AST_ESPI_VW_SYS_EVT) { ++ uint32_t sys_status = readl(AST_ESPI_BASE + ESPI11C); ++ uint32_t sys_event = readl(AST_ESPI_BASE + ESPI098); ++ ++ DBG_ESPI("sys_status : 0x%08X\n", sys_status); ++ if (sys_status & AST_ESPI_HOST_RST_WARN) { ++ DBG_ESPI("HOST_RST_WARN ev: %08X\n", sys_event); ++ if (sys_event & AST_ESPI_HOST_RST_WARN) { ++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) ++ | AST_ESPI_HOST_RST_ACK; ++ writel(v, AST_ESPI_BASE + ESPI098); ++ } ++ } ++ if (sys_status & AST_ESPI_OOB_RST_WARN) { ++ DBG_ESPI("OOB_RST_WARN ev: %08X\n", sys_event); ++ if (sys_event & AST_ESPI_OOB_RST_WARN) { ++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) ++ | AST_ESPI_OOB_RST_ACK; ++ writel(v, AST_ESPI_BASE + ESPI098); ++ } ++ } ++ writel(sys_status, AST_ESPI_BASE + ESPI11C); // clear status ++ } ++ ++ if (irq_status & AST_ESPI_VW_SYS_EV1) { ++ uint32_t sys1_status = readl(AST_ESPI_BASE + ESPI12C); ++ uint32_t sys1_event = readl(AST_ESPI_BASE + ESPI104); ++ ++ DBG_ESPI("sys1_status : 0x%08X\n", sys1_status); ++ if (sys1_status & AST_ESPI_SUS_WARN) { ++ DBG_ESPI("SUS WARN ev: %08X\n", sys1_event); ++ if (sys1_event & AST_ESPI_SUS_WARN) { ++ uint32_t v = readl(AST_ESPI_BASE + ESPI104) ++ | AST_ESPI_SUS_ACK; ++ writel(v, AST_ESPI_BASE + ESPI104); ++ } ++ } ++ writel(sys1_status, AST_ESPI_BASE + ESPI12C); // clear status ++ } ++ writel(irq_status, AST_ESPI_BASE + ESPI008); // clear irq_status ++ return 0; ++} ++ ++static void espi_handshake_ack(void) ++{ ++ // IRQ only serviced if strapped, so no strap check ++ if (!(readl(AST_ESPI_BASE + ESPI098) & AST_ESPI_SL_BT_STATUS)) { ++ DBG_ESPI("Setting espi slave boot done\n"); ++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) ++ | AST_ESPI_SL_BT_STATUS | AST_ESPI_SL_BT_DONE; ++ writel(v, AST_ESPI_BASE + ESPI098); ++ } ++ ++ if (readl(AST_ESPI_BASE + ESPI104) & AST_ESPI_SUS_WARN) { ++ DBG_ESPI("Boot SUS WARN set %08x\n", ++ readl(AST_ESPI_BASE + ESPI104)); ++ uint32_t v = readl(AST_ESPI_BASE + ESPI104) | AST_ESPI_SUS_ACK; ++ writel(v, AST_ESPI_BASE + ESPI104); ++ } ++} ++ ++void espi_init(void) ++{ ++ if (readl(AST_SCU_BASE + AST_SCU_HW_STRAP1) ++ & SCU_HW_STRAP_ESPI_ENABLED) { ++ uint32_t v; ++ DBG_ESPI("espi_init\n"); ++ ++ /* Block flash access from Host */ ++ v = readl(AST_ESPI_BASE + ESPI000) & ~AST_ESPI_FLASH_SW_CHRDY; ++ v |= AST_ESPI_FLASH_SW_READ | AST_ESPI_OOB_CHRDY; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ ++ /* Set SIO register 0x28 to 0xa8 as a faked ASPEED ChipID for ++ * BIOS using in eSPI mode */ ++ v = readl(AST_LPC_BASE + SCR0SIO) & ~0x000000ff; ++ writel(v, AST_LPC_BASE + SCR0SIO); ++ v = readl(AST_LPC_BASE + SCR0SIO) | 0xa8; ++ writel(v, AST_LPC_BASE + SCR0SIO); ++ ++ v = readl(AST_ESPI_BASE + ESPI000) | AST_ESPI_OOB_CHRDY; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ ++ writel(0, AST_ESPI_BASE + ESPI110); ++ writel(0, AST_ESPI_BASE + ESPI114); ++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN, ++ AST_ESPI_BASE + ESPI118); ++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN, ++ AST_ESPI_BASE + ESPI094); ++ ++ writel(AST_ESPI_SUS_WARN, ++ AST_ESPI_BASE + ESPI120); // int type 0 susp warn ++ writel(0, AST_ESPI_BASE + ESPI124); ++ writel(0, AST_ESPI_BASE + ESPI128); ++ writel(AST_ESPI_SUS_WARN, ++ AST_ESPI_BASE ++ + ESPI100); // Enable sysev1 ints for susp warn ++ ++ writel(AST_ESPI_IEN_SYS_EV, ++ AST_ESPI_BASE + ESPI00C); // Enable only sys events ++ ++ espi_handshake_ack(); ++ ++ request_irq(IRQ_SRC_ESPI, espi_irq_handler); ++ } else { ++ DBG_ESPI("No espi strap\n"); ++ } ++} +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +new file mode 100644 +index 0000000000..e79235c8d0 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -0,0 +1,16 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * 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; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++ ++extern void espi_init(void); ++void ast_g5_intel(void) ++{ ++ espi_init(); ++} +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index 2472aa3603..d41ef9cbd3 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -18,6 +18,8 @@ + + DECLARE_GLOBAL_DATA_PTR; + ++extern void ast_g5_intel(void); ++ + int board_early_init_f(void) + { + /* make sure uart5 is using 24MHz clock */ +@@ -34,6 +36,7 @@ int board_init(void) + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; + gd->flags = 0; + ++ ast_g5_intel(); + return 0; + } + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch new file mode 100644 index 000000000..e16b0f158 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch @@ -0,0 +1,160 @@ +From c3b44c02392d33cfec85056fd323d93fdc6e523f Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 12:09:52 -0800 +Subject: [PATCH] add sgio support for port80 snoop post LEDs + +This ties together the port 80 snooping to the SGPIO output that +ultimately drives the POST code LEDs. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Change-Id: Iaa1b91cd40f4b6323dba0598da373cb631459e66 +--- + arch/arm/include/asm/arch-aspeed/ast_scu.h | 1 + + arch/arm/mach-aspeed/ast-scu.c | 8 +++ + board/aspeed/ast-g5/ast-g5-intel.c | 96 ++++++++++++++++++++++++++++++ + 3 files changed, 105 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h +index 06825ce..369c4e3 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h ++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h +@@ -45,6 +45,7 @@ extern u32 ast_scu_get_vga_memsize(void); + extern void ast_scu_init_eth(u8 num); + extern void ast_scu_multi_func_eth(u8 num); + extern void ast_scu_multi_func_romcs(u8 num); ++extern void ast_scu_multi_func_sgpio(void); + + void ast_config_uart5_clk(void); + +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index d27f3d3..3a9ba05 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -449,6 +449,14 @@ void ast_scu_multi_func_romcs(u8 num) + SCU_FUN_PIN_ROMCS(num), AST_SCU_FUN_PIN_CTRL3); + } + ++void ast_scu_multi_func_sgpio(void) ++{ ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL2) | ++ SCU_FUN_PIN_SGPMI | SCU_FUN_PIN_SGPMO | ++ SCU_FUN_PIN_SGPMLD | SCU_FUN_PIN_SGPMCK, ++ AST_SCU_FUN_PIN_CTRL2); ++} ++ + u32 ast_scu_revision_id(void) + { + int i; +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index e79235c..c2a8b33 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -8,9 +8,105 @@ + */ + + #include <common.h> ++#include <asm/io.h> ++#include <asm/arch/regs-scu.h> ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/aspeed.h> ++ ++#include "ast-g5.h" ++ ++#define LPC_SNOOP_ADDR 0x80 ++#define HICR5 0x080 /* Host Interface Control Register 5 */ ++#define HICR6 0x084 /* Host Interface Control Register 6 */ ++#define HICR7 0x088 /* Host Interface Control Register 7 */ ++#define HICR8 0x08c /* Host Interface Control Register 8 */ ++#define SNPWADR 0x090 /* LPC Snoop Address Register */ ++#define SNPWDR 0x094 /* LPC Snoop Data Register */ ++#define HICR9 0x098 /* Host Interface Control Register 9 */ ++#define HICRA 0x09c /* Host Interface Control Register A */ ++#define LHCR0 0x0a0 /* LPC Host Control Register 0 */ ++#define LHCR1 0x0a4 /* LPC Host Control Register 1 */ ++#define LHCR2 0x0a8 /* LPC Host Control Register 2 */ ++#define LHCR3 0x0ac /* LPC Host Control Register 3 */ ++#define LHCR4 0x0b0 /* LPC Host Control Register 4 */ ++#define LHCR5 0x0b4 /* LPC Host Control Register 5 */ ++#define LHCR6 0x0b8 /* LPC Host Control Register 6 */ ++#define LHCR7 0x0bc /* LPC Host Control Register 7 */ ++#define LHCR8 0x0c0 /* LPC Host Control Register 8 */ ++#define PCCR6 0x0c4 /* Post Code Control Register 6 */ ++#define LHCRA 0x0c8 /* LPC Host Control Register A */ ++#define LHCRB 0x0cc /* LPC Host Control Register B */ ++#define PCCR4 0x0d0 /* Post Code Control Register 4 */ ++#define PCCR5 0x0d4 /* Post Code Control Register 5 */ ++#define HICRB 0x100 /* Host Interface Control Register B */ ++#define HICRC 0x104 /* Host Interface Control Register C */ ++/* HICR5 Bits */ ++#define HICR5_EN_SIOGIO (1 << 31) /* Enable SIOGIO */ ++#define HICR5_EN80HGIO (1 << 30) /* Enable 80hGIO */ ++#define HICR5_SEL80HGIO (0x1f << 24) /* Select 80hGIO */ ++#define SET_SEL80HGIO(x) ((x & 0x1f) << 24) /* Select 80hGIO Offset */ ++#define HICR5_UNKVAL_MASK 0x1FFF0000 /* Bits with unknown values on reset */ ++#define HICR5_ENINT_SNP0W (1 << 1) /* Enable Snooping address 0 */ ++#define HICR5_EN_SNP0W (1 << 0) /* Enable Snooping address 0 */ ++ ++/* HRCR6 Bits */ ++#define HICR6_STR_SNP0W (1 << 0) /* Interrupt Status Snoop address 0 */ ++#define HICR6_STR_SNP1W (1 << 1) /* Interrupt Status Snoop address 1 */ ++ ++/* HICRB Bits */ ++#define HICRB_EN80HSGIO (1 << 13) /* Enable 80hSGIO */ ++ ++#define SGPIO_CLK_DIV(N) ((N) << 16) ++#define SGPIO_BYTES(N) ((N) << 6) ++#define SGPIO_ENABLE 1 ++#define GPIO254 0x254 ++ ++static void sgpio_init(void) ++{ ++ uint32_t value; ++ /* ++ 33.4.2 ++ LPC port80h direct to SGPIO ++ In AST2500 SGPIO, it supports output data from 80h. It always uses SGPIOA. ++ 1. Configure LPC snoop function. ++ (a) Set SNPWADR(0x1e789090)[15:0] to 0x80. ++ (b) Set HICR5(0x1e789080)[0] to 1 to enable snoop. ++ 2. Configure SGPIO ++ (a) Set GPIO254[9:6] to larger than or equal to 0x1. ++ (b) Set GPIO254[0] to 1 to enable SGPIO. ++ 3. Set SuperIO ++ (a) Set SIOR7 30h to 0x40. ++ */ ++ /* make sure multi-pin stuff goes in our favor */ ++ ast_scu_multi_func_sgpio(); ++ ++ /* set lpc snoop #0 to port 0x80 */ ++ value = readl(AST_LPC_BASE + SNPWADR) & 0xffff0000; ++ writel(value | LPC_SNOOP_ADDR, AST_LPC_BASE + SNPWADR); ++ ++ /* clear interrupt status */ ++ value = readl(AST_LPC_BASE + HICR6); ++ value |= HICR6_STR_SNP0W | HICR6_STR_SNP1W; ++ writel(value, AST_LPC_BASE + HICR6); ++ ++ /* enable lpc snoop #0 and SIOGIO */ ++ value = readl(AST_LPC_BASE + HICR5) & ~(HICR5_UNKVAL_MASK); ++ value |= HICR5_EN_SIOGIO | HICR5_EN_SNP0W; ++ writel(value, AST_LPC_BASE + HICR5); ++ ++ ++ /* enable port80h snoop on SGPIO */ ++ value = readl(AST_LPC_BASE + HICRB) | HICRB_EN80HSGIO; ++ writel(value, AST_LPC_BASE + HICRB); ++ ++ /* set the gpio clock to pclk/(2*(5+1)) or ~2 MHz */ ++ value = SGPIO_CLK_DIV(256) | SGPIO_BYTES(10) | SGPIO_ENABLE; ++ writel(value, AST_GPIO_BASE + GPIO254); ++} + + extern void espi_init(void); + void ast_g5_intel(void) + { + espi_init(); ++ sgpio_init(); + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch new file mode 100644 index 000000000..a49f196ac --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch @@ -0,0 +1,414 @@ +From 89728d8c255204c8d9ec46a1dc0d412b04708f22 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 09:58:01 -0800 +Subject: [PATCH 4/7] Add basic GPIO support + +Add a table of well-known gpios (such as FP LEDs and FF UPD jumper) and +initialize them at boot. + +Add a mechanism to get/set well known gpios from command line. + +Change-Id: I4136a5ccb048b3604f13b17ea0c18a4bc596c249 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-gpio.c | 195 +++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-gpio.h | 102 +++++++++++++++ + board/aspeed/ast-g5/ast-g5-intel.c | 42 +++++++ + board/aspeed/ast-g5/ast-g5.h | 1 + + 5 files changed, 341 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-gpio.c + create mode 100644 board/aspeed/ast-g5/ast-g5-gpio.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 58e0c648f4..2970ae5741 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -2,3 +2,4 @@ obj-y += ast-g5.o + obj-y += ast-g5-intel.o + obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o ++obj-y += ast-g5-gpio.o +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.c b/board/aspeed/ast-g5/ast-g5-gpio.c +new file mode 100644 +index 0000000000..d596c15914 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-gpio.c +@@ -0,0 +1,195 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * 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; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++#include <asm/io.h> ++#include <asm/arch/regs-scu.h> ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/aspeed.h> ++ ++#include "ast-g5.h" ++#include "ast-g5-gpio.h" ++ ++typedef struct _gpio_bases { ++ uint32_t u32ddr; /* data and direction registers */ ++ uint32_t u32intcfg; /* interrupt config */ ++ uint32_t u32debounce; /* debounce config */ ++ uint32_t u32cmdsrc; /* command source config */ ++} sGPIO_BASES; ++ ++static const sGPIO_BASES GPIO_BASES[] = { ++ /* ABCD */ ++ {AST_GPIO_BASE + 0x0000, AST_GPIO_BASE + 0x0008, ++ AST_GPIO_BASE + 0x0040, AST_GPIO_BASE + 0x0060}, ++ /* EFGH */ ++ {AST_GPIO_BASE + 0x0020, AST_GPIO_BASE + 0x0028, ++ AST_GPIO_BASE + 0x0048, AST_GPIO_BASE + 0x0068}, ++ /* IJKL */ ++ {AST_GPIO_BASE + 0x0070, AST_GPIO_BASE + 0x0098, ++ AST_GPIO_BASE + 0x00b0, AST_GPIO_BASE + 0x0090}, ++ /* MNOP */ ++ {AST_GPIO_BASE + 0x0078, AST_GPIO_BASE + 0x00e8, ++ AST_GPIO_BASE + 0x0100, AST_GPIO_BASE + 0x00e0}, ++ /* QRST */ ++ {AST_GPIO_BASE + 0x0080, AST_GPIO_BASE + 0x0118, ++ AST_GPIO_BASE + 0x0130, AST_GPIO_BASE + 0x0110}, ++ /* UVWX */ ++ {AST_GPIO_BASE + 0x0088, AST_GPIO_BASE + 0x0148, ++ AST_GPIO_BASE + 0x0160, AST_GPIO_BASE + 0x0140}, ++ /* YZAB */ ++ {AST_GPIO_BASE + 0x01e0, AST_GPIO_BASE + 0x0178, ++ AST_GPIO_BASE + 0x0190, AST_GPIO_BASE + 0x0170}, ++ /* AC__ */ ++ {AST_GPIO_BASE + 0x01e8, AST_GPIO_BASE + 0x01a8, ++ AST_GPIO_BASE + 0x01c0, AST_GPIO_BASE + 0x01a0}, ++}; ++ ++static size_t gpio_max = 0; ++static const GPIOValue * gpio_table = NULL; ++ ++void gpio_set_value(int n, int asserted) ++{ ++ uint8_t port; ++ uint8_t pin; ++ uint32_t base; ++ uint8_t shift; ++ uint8_t assert; ++ uint32_t gpio_value; ++ ++ if (n >= gpio_max || !gpio_table) { ++ return; ++ } ++ port = GPIO_PORT(gpio_table[n].u8PortPin); ++ assert = GPIO_PORT(gpio_table[n].u8Value); ++ pin = GPIO_PIN(gpio_table[n].u8PortPin); ++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr; ++ shift = GPIO_SHIFT(port, pin); ++ ++ gpio_value = readl(base + GPIO_DATA_VALUE); ++ if ((assert &&asserted) || !(assert || asserted)) { ++ // set the bit ++ gpio_value |= (1 << shift); ++ } else { ++ // clear the bit ++ gpio_value &= ~(1 << shift); ++ } ++ writel(gpio_value, base + GPIO_DATA_VALUE); ++} ++ ++int gpio_get_value(int n) ++{ ++ uint8_t port; ++ uint8_t pin; ++ uint32_t base; ++ uint8_t shift; ++ uint8_t assert; ++ uint32_t gpio_value; ++ ++ if (n >= gpio_max || !gpio_table) { ++ return -1; ++ } ++ port = GPIO_PORT(gpio_table[n].u8PortPin); ++ assert = GPIO_PORT(gpio_table[n].u8Value); ++ pin = GPIO_PIN(gpio_table[n].u8PortPin); ++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr; ++ shift = GPIO_SHIFT(port, pin); ++ ++ gpio_value = readl(base + GPIO_DATA_VALUE); ++ gpio_value >>= shift; ++ gpio_value &= 1; ++ gpio_value ^= assert; ++ return !gpio_value; ++} ++ ++void gpio_init(const GPIOValue* table, size_t count) ++{ ++ uint32_t pclk, value; ++ int i; ++ ++ gpio_table = table; ++ gpio_max = count; ++ /* set up the debounce timers (in units of PCLK cycles) */ ++ pclk = ast_get_ahbclk(); ++ /* GPIO_DEBOUNCE_120us */ ++ writel((pclk / 1000000) * 120, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_0); ++ /* GPIO_DEBOUNCE_8ms */ ++ writel((pclk / 1000000) * 8000, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_1); ++ /* GPIO_DEBOUNCE_16ms */ ++ writel((pclk / 1000000) * 16000, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_2); ++ ++ for (i = 0; i < gpio_max; i++) { ++ uint8_t port; ++ uint8_t pin; ++ uint32_t base; ++ uint8_t shift; ++ ++ port = GPIO_PORT(gpio_table[i].u8PortPin); ++ pin = GPIO_PIN(gpio_table[i].u8PortPin); ++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr; ++ shift = GPIO_SHIFT(port, pin); ++ ++ /* set direction */ ++ value = readl(base + GPIO_DIRECTION); ++ if (gpio_table[i].u8PinCFG & GPCFG_OUTPUT_EN) ++ value |= (1 << shift); ++ else ++ value &= ~(1 << shift); ++ writel(value, base + GPIO_DIRECTION); ++ ++ /* set data value */ ++ value = readl(base + GPIO_DATA_VALUE); ++ if (gpio_table[i].u8Value) ++ value |= (1 << shift); ++ else ++ value &= ~(1 << shift); ++ writel(value, base + GPIO_DATA_VALUE); ++ ++ /* set debounce */ ++ base = GPIO_BASES[GPIO_GROUP(port)].u32debounce; ++ value = readl(base + GPIO_DEBOUNCE_SEL_0); ++ if (gpio_table[i].u8Debounce & 0x01) ++ value |= (1 << shift); ++ else ++ value &= ~(1 << shift); ++ writel(value, base + GPIO_DEBOUNCE_SEL_0); ++ value = readl(base + GPIO_DEBOUNCE_SEL_1); ++ if (gpio_table[i].u8Debounce & 0x02) ++ value |= (1 << shift); ++ else ++ value &= ~(1 << shift); ++ writel(value, base + GPIO_DEBOUNCE_SEL_1); ++ } ++} ++ ++int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ int n; ++ if (argc < 3) { ++ return 1; ++ } ++ n = simple_strtoul(argv[2], NULL, 16); ++ if (argv[1][0] == 'g') { ++ printf("%d\n", gpio_get_value(n)); ++ return 0; ++ } ++ if (argc < 4) { ++ return 1; ++ } ++ if (argv[1][0] == 's') { ++ int value; ++ value = simple_strtoul(argv[3], NULL, 16); ++ gpio_set_value(n, value); ++ return 0; ++ } ++ ++ return 1; ++} ++U_BOOT_CMD(gpio, 4, 0, do_gpio, ++ "do stuff with gpios <set|get> [n] [value]", ++ ""); +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.h b/board/aspeed/ast-g5/ast-g5-gpio.h +new file mode 100644 +index 0000000000..a820c0fcad +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-gpio.h +@@ -0,0 +1,102 @@ ++#ifndef __HW_GPIO_H__ ++#define __HW_GPIO_H__ ++ ++#define GPIO_PORT_A 0 ++#define GPIO_PORT_B 1 ++#define GPIO_PORT_C 2 ++#define GPIO_PORT_D 3 ++#define GPIO_PORT_E 4 ++#define GPIO_PORT_F 5 ++#define GPIO_PORT_G 6 ++#define GPIO_PORT_H 7 ++#define GPIO_PORT_I 8 ++#define GPIO_PORT_J 9 ++#define GPIO_PORT_K 10 ++#define GPIO_PORT_L 11 ++#define GPIO_PORT_M 12 ++#define GPIO_PORT_N 13 ++#define GPIO_PORT_O 14 ++#define GPIO_PORT_P 15 ++#define GPIO_PORT_Q 16 ++#define GPIO_PORT_R 17 ++#define GPIO_PORT_S 18 ++#define GPIO_PORT_T 19 ++#define GPIO_PORT_U 20 ++#define GPIO_PORT_V 21 ++#define GPIO_PORT_W 22 ++#define GPIO_PORT_X 23 ++#define GPIO_PORT_Y 24 ++#define GPIO_PORT_Z 25 ++#define GPIO_PORT_AA 26 ++#define GPIO_PORT_AB 27 ++#define GPIO_PORT_AC 28 ++ ++#define GPIO_PIN_0 0 ++#define GPIO_PIN_1 1 ++#define GPIO_PIN_2 2 ++#define GPIO_PIN_3 3 ++#define GPIO_PIN_4 4 ++#define GPIO_PIN_5 5 ++#define GPIO_PIN_6 6 ++#define GPIO_PIN_7 7 ++ ++#define GPIO_DEBOUNCE_TIMER_0 0x50 ++#define GPIO_DEBOUNCE_TIMER_1 0x54 ++#define GPIO_DEBOUNCE_TIMER_2 0x58 ++ ++/* relative to u32ddr base */ ++#define GPIO_DATA_VALUE 0x00 ++#define GPIO_DIRECTION 0x04 ++/* relative to u32intcfg base */ ++#define GPIO_INT_ENABLE 0x00 ++#define GPIO_INT_SENSE0 0x04 ++#define GPIO_INT_SENSE1 0x18 ++#define GPIO_INT_SENSE2 0x1c ++#define GPIO_INT_STATUS 0x20 ++#define GPIO_RESET_TOL 0x24 ++/* relative to u32debounce base */ ++#define GPIO_DEBOUNCE_SEL_0 0 ++#define GPIO_DEBOUNCE_SEL_1 4 ++/* relative to u32cmdsrc base */ ++#define GPIO_CMD_SRC_0 0 ++#define GPIO_CMD_SRC_1 4 ++ ++#define PORT_PIN(PORT, PIN) (((PORT) << 3) | ((PIN)&0x07)) ++#define GPIO_PIN(N) (N & 0x07) ++#define GPIO_PORT(N) (N >> 3) ++#define GPIO_SHIFT(PORT, PIN) ((PIN) + (((PORT) % 4) * 8)) ++#define GPIO_GROUP(PORT) ((PORT) / 4) ++ ++#define ID_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_6) ++#define GRN_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_4) ++#define AMB_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_5) ++#define FORCE_BMC_UPDATE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_0) ++#define TPM_EN_PULSE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_6) ++ ++ ++// GPIO Configuration Register bits ++#define GPCFG_EVENT_TO_SMI (1 << 7) // 1 == enabled ++#define GPCFG_EVENT_TO_IRQ (1 << 6) // 1 == enabled ++#define GPCFG_DEBOUNCE_EN (1 << 5) // 1 == input debounce, 0 == pulse output ++#define GPCFG_ACTIVE_HIGH (1 << 4) // 1 == Active high ++#define GPCFG_LEVEL_TRIG (1 << 3) // 1 == level (default), 0 == edge ++#define GPCFG_OUTPUT_EN (1 << 0) // 1 == Output enabled ++ ++// GPIO Debounce and Blink Configuration Register bits ++#define GPIO_DEBOUNCE_NONE 0x00 ++#define GPIO_DEBOUNCE_60US 0x01 ++#define GPIO_DEBOUNCE_8MS 0x02 ++#define GPIO_DEBOUNCE_16MS 0x03 ++ ++typedef struct { ++ uint8_t u8PortPin; ++ uint8_t u8PinCFG; ++ uint8_t u8Value; ++ uint8_t u8Debounce; ++} GPIOValue; ++ ++void gpio_init(const GPIOValue* table, size_t count); ++void gpio_set_value(int n, int asserted); ++int gpio_get_value(int n); ++ ++#endif /* __HW_GPIO_H__ */ +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index fca4d91115..252a05dd73 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -14,6 +14,47 @@ + #include <asm/arch/aspeed.h> + + #include "ast-g5.h" ++#include "ast-g5-gpio.h" ++ ++/* Names to match the GPIOs */ ++enum gpio_names { ++ GPIO_ID_LED = 0, ++ GPIO_GREEN_LED, ++ GPIO_AMBER_LED, ++ GPIO_FF_UPD_JUMPER, ++ GPIO_ENABLE_TPM_PULSE, ++}; ++ ++#define GPIO_CFG_DEFAULT (GPCFG_ACTIVE_HIGH | GPCFG_LEVEL_TRIG) ++// Active High, Level, Output Disabled ++ ++#define GPIO_CFG_FP_LED (GPCFG_OUTPUT_EN) ++// Active High, Pull-up, Level, Output Disabled ++ ++// Format is: ++// GPIO PORT, GPIO PIN Number, GPIO PIN Configuration, GPIO PIN Value, GPIO ++// Debounce/Blink Setting ++static const GPIOValue gpio_table[] = { ++ /* ID LED pin S6 - low asserted, 0=on */ ++ [GPIO_ID_LED] = {ID_LED_PORT_PIN, GPIO_CFG_FP_LED, 0, ++ GPIO_DEBOUNCE_NONE}, ++ ++ /* Green LED pin S4 - high asserted, 0=off */ ++ [GPIO_GREEN_LED] = {GRN_LED_PORT_PIN, GPIO_CFG_FP_LED, 1, ++ GPIO_DEBOUNCE_NONE}, ++ ++ /* Amber LED pin S5 - high asserted, 0=off */ ++ [GPIO_AMBER_LED] = {AMB_LED_PORT_PIN, GPIO_CFG_FP_LED, 1, ++ GPIO_DEBOUNCE_NONE}, ++ ++ /* Force Update Jumper -- pin D0 */ ++ [GPIO_FF_UPD_JUMPER] = {FORCE_BMC_UPDATE_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ ++ /* Enable Pulse -- pin D6 */ ++ [GPIO_ENABLE_TPM_PULSE] = {PORT_PIN(GPIO_PORT_D, GPIO_PIN_6), ++ GPIO_CFG_DEFAULT, 0, GPIO_DEBOUNCE_8MS}, ++}; + + #define LPC_SNOOP_ADDR 0x80 + #define HICR5 0x080 /* Host Interface Control Register 5 */ +@@ -107,6 +148,7 @@ static void sgpio_init(void) + extern void espi_init(void); + void ast_g5_intel(void) + { ++ gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); + sgpio_init(); + } +diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h +index 9fd10eccb3..908db1477b 100644 +--- a/board/aspeed/ast-g5/ast-g5.h ++++ b/board/aspeed/ast-g5/ast-g5.h +@@ -3,5 +3,6 @@ + + #include <common.h> + #include "ast-g5-irq.h" ++#include "ast-g5-gpio.h" + + #endif /* _AST_G5_H_ */ +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch new file mode 100644 index 000000000..c97e6d74f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch @@ -0,0 +1,98 @@ +From 1f710737f2fe8dea4bc5ebef1e6011de294764b4 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 14:59:04 -0800 +Subject: [PATCH] Update Force Firmware Update Jumper to use new gpio API + +Add a function that allows easy reading of the FFUJ from other +functions, such as autoboot. + +Change-Id: I8ead931e9dd828522095a0ef386875be652ec885 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + .../include/asm/arch-aspeed/ast-g5-intel.h | 19 +++++++++++++++++++ + arch/arm/include/asm/arch-aspeed/platform.h | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 5 +++++ + common/autoboot.c | 6 ++++++ + 4 files changed, 31 insertions(+) + create mode 100644 arch/arm/include/asm/arch-aspeed/ast-g5-intel.h + +diff --git a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +new file mode 100644 +index 0000000000..cd9a0994fa +--- /dev/null ++++ b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * 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; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#ifndef __AST_INTEL_G5_H__ ++#define __AST_INTEL_G5_H__ ++ ++#define AST_G5_INTEL 1 ++ ++#ifndef __ASSEMBLY__ ++int intel_force_firmware_jumper_enabled(void); ++#endif ++ ++#endif /* __AST_INTEL_G5_H__ */ +diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h +index 9f339e913a..3ea1c99089 100644 +--- a/arch/arm/include/asm/arch-aspeed/platform.h ++++ b/arch/arm/include/asm/arch-aspeed/platform.h +@@ -27,6 +27,7 @@ + #include <asm/arch/ast2400_platform.h> + #elif defined(AST_SOC_G5) + #include <asm/arch/ast_g5_platform.h> ++#include <asm/arch/ast-g5-intel.h> + #define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */ + #else + #err "No define for platform.h" +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 252a05dd73..58ad6a55b8 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -145,6 +145,11 @@ static void sgpio_init(void) + writel(value, AST_GPIO_BASE + GPIO254); + } + ++int intel_force_firmware_jumper_enabled(void) ++{ ++ return gpio_get_value(GPIO_FF_UPD_JUMPER); ++} ++ + extern void espi_init(void); + void ast_g5_intel(void) + { +diff --git a/common/autoboot.c b/common/autoboot.c +index c52bad84a4..d66c0fa63a 100644 +--- a/common/autoboot.c ++++ b/common/autoboot.c +@@ -14,6 +14,7 @@ + #include <menu.h> + #include <post.h> + #include <u-boot/sha256.h> ++#include <asm/arch/platform.h> + + DECLARE_GLOBAL_DATA_PTR; + +@@ -259,6 +260,11 @@ static int abortboot(int bootdelay) + { + int abort = 0; + ++# ifdef AST_G5_INTEL ++ if (intel_force_firmware_jumper_enabled()) ++ return 1; ++# endif ++ + if (bootdelay >= 0) + abort = __abortboot(bootdelay); + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch new file mode 100644 index 000000000..11a474b96 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch @@ -0,0 +1,160 @@ +From 83d67b5b3cbffcefda5efdc0060b9e30f44c9aca Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 14:44:49 -0800 +Subject: [PATCH 6/7] Add basic timer support for Aspeed g5 in U-Boot + +Timers will be used for timing events and making blinky LEDs. This just +adds the API and infrastructure. + +Change-Id: I8ff03b26070b43a47fb970ddf6124d6c3f29b058 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 1 + + board/aspeed/ast-g5/ast-g5-timer.c | 66 ++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-timer.h | 27 ++++++++++++ + board/aspeed/ast-g5/ast-g5.h | 1 + + 5 files changed, 96 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-timer.c + create mode 100644 board/aspeed/ast-g5/ast-g5-timer.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 2970ae5741..90224333c4 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -3,3 +3,4 @@ obj-y += ast-g5-intel.o + obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o + obj-y += ast-g5-gpio.o ++obj-y += ast-g5-timer.o +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 58ad6a55b8..23bf4e4352 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -15,6 +15,7 @@ + + #include "ast-g5.h" + #include "ast-g5-gpio.h" ++#include "ast-g5-timer.h" + + /* Names to match the GPIOs */ + enum gpio_names { +diff --git a/board/aspeed/ast-g5/ast-g5-timer.c b/board/aspeed/ast-g5/ast-g5-timer.c +new file mode 100644 +index 0000000000..56157222d9 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-timer.c +@@ -0,0 +1,66 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * 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; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++#include <asm/io.h> ++#include <asm/arch/regs-scu.h> ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/aspeed.h> ++ ++#include "ast-g5.h" ++#include "ast-g5-timer.h" ++#include "ast-g5-irq.h" ++ ++static const int timer_irqs[] = {16, 17, 18, 35, 37, 37, 38, 39}; ++/* offsets from AST_TIMER_BASE for each timer */ ++static const uint32_t timer_bases[] = {0, 0x10, 0x20, 0x40, ++ 0x50, 0x60, 0x70, 0x80}; ++#define TIMER_1MHZ_CLK_COUNT 1000000u ++#define TIMER_ENABLE 1 ++#define TIMER_1MHZ_CLK_SEL 2 ++#define TIMER_ENABLE_IRQ 4 ++#define TIMER_ENABLE_PULSE 8 ++#define TIMER_CONTROL 0x30 ++#define TIMER_RELOAD 0x04 ++ ++void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler) ++{ ++ if (n < 0 || n > 7) { ++ return; ++ } ++ uint32_t tctrl = readl(AST_TIMER_BASE + TIMER_CONTROL); ++ writel(tctrl & ~(0x0f << (n * 4)), AST_TIMER_BASE + TIMER_CONTROL); ++ ++ // figure out best base for requested frequency ++ // (this will give 1MHz clock preference if period is within 1ms of ++ // requested) ++ uint32_t v = TIMER_1MHZ_CLK_COUNT / freq; ++ if (v > 1000 || v * freq == TIMER_1MHZ_CLK_COUNT) { ++ tctrl |= (TIMER_1MHZ_CLK_SEL << (n * 4)); ++ } else { ++ uint32_t pclk = ast_get_ahbclk(); ++ v = pclk / freq; ++ } ++ writel(v, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD); ++ if (handler) { ++ request_irq(timer_irqs[n], handler); ++ tctrl |= (TIMER_ENABLE_IRQ << (n * 4)); ++ } ++ tctrl |= (TIMER_ENABLE << (n * 4)); ++ writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL); ++} ++ ++void timer_disable(int n) ++{ ++ if (n < 0 || n > 7) { ++ return; ++ } ++ uint32_t tctrl = readl(AST_TIMER_BASE + TIMER_CONTROL); ++ writel(tctrl & ~(0x0f << (n * 4)), AST_TIMER_BASE + TIMER_CONTROL); ++} +diff --git a/board/aspeed/ast-g5/ast-g5-timer.h b/board/aspeed/ast-g5/ast-g5-timer.h +new file mode 100644 +index 0000000000..4b1ac28a9f +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-timer.h +@@ -0,0 +1,27 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * 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; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#ifndef __AST_G5_TIMER_H__ ++#define __AST_G5_TIMER_H__ ++ ++#include <common.h> ++ ++#define TIMER_1 0 ++#define TIMER_2 1 ++#define TIMER_3 2 ++#define TIMER_4 3 ++#define TIMER_5 4 ++#define TIMER_6 5 ++#define TIMER_7 6 ++#define TIMER_8 7 ++ ++void timer_enable(int n, uint32_t freq, interrupt_handler_t handler); ++void timer_disable(int n); ++ ++#endif /* __AST_G5_TIMER_H__ */ +diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h +index 908db1477b..28fe5eafcb 100644 +--- a/board/aspeed/ast-g5/ast-g5.h ++++ b/board/aspeed/ast-g5/ast-g5.h +@@ -4,5 +4,6 @@ + #include <common.h> + #include "ast-g5-irq.h" + #include "ast-g5-gpio.h" ++#include "ast-g5-timer.h" + + #endif /* _AST_G5_H_ */ +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch new file mode 100644 index 000000000..5a2c2206f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch @@ -0,0 +1,144 @@ +From f0e3631ea3005640f988727f051106d83b5dfdaf Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 12:16:53 -0800 +Subject: [PATCH 7/7] Add status and ID LED support + +Add status (amber and green) and ID (blue) LED support. In the +bootloader phase, the LEDs should be blinking. When booting linux, they +should turn to a fixed state. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Change-Id: Ic9595621b21000ef465ff57ed2047855296e2714 +--- + board/aspeed/ast-g5/ast-g5-intel.c | 118 +++++++++++++++++++++++++++++ + 1 file changed, 118 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 23bf4e4352..5ff2cbd0e2 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -146,6 +146,110 @@ static void sgpio_init(void) + writel(value, AST_GPIO_BASE + GPIO254); + } + ++/* running the timer at 48 hertz will easily give a 24Hz blink */ ++#define TICK_HZ 48 ++#define BLINK_DELAY(HZ) ((int)((TICK_HZ / (HZ)) / 2) - 1) ++typedef enum { ++ /* ++ * Identifies the control request for the ID LED. ++ */ ++ EIDLED_Initialize = 0, ++ EIDLED_Tick, ++ EIDLED_Toggle, ++ EIDLED_Off, ++ EIDLED_On, ++ EIDLED_Blink, ++ EIDLED_Blink_24HZ = EIDLED_Blink + BLINK_DELAY(24), ++ EIDLED_Blink_12HZ = EIDLED_Blink + BLINK_DELAY(12), ++ EIDLED_Blink_6HZ = EIDLED_Blink + BLINK_DELAY(6), ++ EIDLED_Blink_3HZ = EIDLED_Blink + BLINK_DELAY(3), ++ EIDLED_Blink_1HZ = EIDLED_Blink + BLINK_DELAY(1), ++ EIDLED_Blink_0_5HZ = EIDLED_Blink + BLINK_DELAY(0.5), ++} EIDLEDControl; ++ ++struct led_info { ++ int gpio; ++ EIDLEDControl mode; ++ int count; ++ int state; ++}; ++ ++static struct led_info s_led_info[] = { ++ [GPIO_ID_LED] = {GPIO_ID_LED, EIDLED_Blink_3HZ, 1, 0}, ++ [GPIO_GREEN_LED] = {GPIO_GREEN_LED, EIDLED_Off, 0, 0}, ++ [GPIO_AMBER_LED] = {GPIO_AMBER_LED, EIDLED_Off, 0, 0}, ++}; ++ ++extern void gpio_set_value(int n, int asserted); ++void id_led_control(int id, int action) ++{ ++ if (id >= ARRAY_SIZE(s_led_info)) { ++ return; ++ } ++ /* don't bother with LEDs that are not initialized */ ++ if (EIDLED_Initialize == s_led_info[id].mode) { ++ return; ++ } ++ ++ /* check for a blinker action */ ++ if (EIDLED_Tick == action) { ++ if (s_led_info[id].mode < EIDLED_Blink) { ++ return; ++ } ++ /* check countdown for blink */ ++ if (s_led_info[id].count == 0) { ++ s_led_info[id].count = ++ s_led_info[id].mode - EIDLED_Blink; ++ s_led_info[id].state = !s_led_info[id].state; ++ } else { ++ s_led_info[id].count--; ++ return; ++ } ++ } else if (EIDLED_Toggle == action) { ++ s_led_info[id].state = !s_led_info[id].state; ++ s_led_info[id].mode = ++ s_led_info[id].state ? EIDLED_On : EIDLED_Off; ++ } else if (action > EIDLED_Toggle) { ++ s_led_info[id].mode = action; ++ if (EIDLED_Off == action) { ++ s_led_info[id].state = 0; ++ } else if (EIDLED_On == action) { ++ s_led_info[id].state = 1; ++ } else if (action >= EIDLED_Blink) { ++ s_led_info[id].count = action - EIDLED_Blink; ++ /* wait for the next tick */ ++ return; ++ } ++ } else if (EIDLED_Initialize == action) { ++ if (s_led_info[id].mode >= EIDLED_Blink) { ++ s_led_info[id].count = ++ s_led_info[id].mode - EIDLED_Blink; ++ } ++ } ++ gpio_set_value(s_led_info[id].gpio, s_led_info[id].state); ++} ++ ++static void timer8_irq_handler(void *regs) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(s_led_info); i++) { ++ id_led_control(i, EIDLED_Tick); ++ } ++} ++ ++void timer8_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(s_led_info); i++) { ++ id_led_control(i, EIDLED_Initialize); ++ } ++ ++ /* set up the timer to fire at TICK_HZ HZ */ ++ timer_enable(TIMER_8, TICK_HZ, timer8_irq_handler); ++} ++ + int intel_force_firmware_jumper_enabled(void) + { + return gpio_get_value(GPIO_FF_UPD_JUMPER); +@@ -157,4 +269,10 @@ void ast_g5_intel(void) + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); + sgpio_init(); ++ timer8_init(); ++ if (intel_force_firmware_jumper_enabled()) { ++ id_led_control(GPIO_AMBER_LED, EIDLED_On); ++ } else { ++ id_led_control(GPIO_GREEN_LED, EIDLED_On); ++ } + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch new file mode 100644 index 000000000..d235aea62 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch @@ -0,0 +1,132 @@ +From 3134584998f624bb6c4ee11102b0bd9b7bb1cbba Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 15:57:57 -0800 +Subject: [PATCH 1/1] aspeed: add Pwm Driver + +Change-Id: Ia8b80212f7c70aafcc6a71782936ec95cf9b7f38 +--- + board/aspeed/ast-g5/ast-g5-intel.c | 105 +++++++++++++++++++++++++++++ + 1 file changed, 105 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 5ff2cbd0e2..f810ded4e7 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -263,9 +263,114 @@ int intel_force_firmware_jumper_enabled(void) + return gpio_get_value(GPIO_FF_UPD_JUMPER); + } + ++/* PWM offsets */ ++ ++#define PWM_BASE_ADDR 0x1E786000 ++#define PWM_CONTROL 0x00 ++#define PWM_CLOCK_SELECTION 0x04 ++#define PWM_DUTY_CYCLE 0x08 ++#define PWM_M0 0x10 ++#define PWM_M1 0x14 ++#define PWM_N0 0x18 ++#define PWM_N1 0x1c ++#define PWM_CONTROL_EXT 0x40 ++#define PWM_CLOCK_SEL_EXT 0x44 ++#define PWM_O0 0x50 ++#define PWM_O1 0x54 ++#define PWM_CHANNEL_COUNT 8 ++ ++#define PWM_CLK_ENABLE BIT(0) ++#define PWM_DUTY(PCT) (((PCT) * 128) / 100) ++#define PWM_DUTY_VALUE PWM_DUTY(57) ++ ++ ++static inline uint32_t ast_scu_read(uint32_t reg) ++{ ++ uint32_t val = readl(AST_SCU_BASE + reg); ++ ++ debug("ast_scu_read : reg = 0x%08x, val = 0x%08x\n", reg, val); ++ return val; ++} ++ ++static inline void ast_scu_write(uint32_t val, uint32_t reg) ++{ ++ debug("ast_scu_write : reg = 0x%08x, val = 0x%08x\n", reg, val); ++ ++ writel(SCU_PROTECT_UNLOCK, AST_SCU_BASE); ++ writel(val, AST_SCU_BASE + reg); ++#ifdef CONFIG_AST_SCU_LOCK ++ writel(0xaa, AST_SCU_BASE); ++#endif ++} ++ ++static void pwm_init(void) ++{ ++ uint32_t val; ++ uint32_t chan; ++ ++ /* select pwm 0-7 */ ++ val = ast_scu_read(AST_SCU_FUN_PIN_CTRL3); ++ val |= (SCU_FUN_PIN_VPIG7 | SCU_FUN_PIN_VPIG6 | SCU_FUN_PIN_VPIG5 ++ | SCU_FUN_PIN_VPIG4 | SCU_FUN_PIN_VPIG3 | SCU_FUN_PIN_VPIG2 ++ | SCU_FUN_PIN_VPIG1 | SCU_FUN_PIN_VPIG0); ++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL3); ++ ++ /* disable video output mux */ ++ val = ast_scu_read(AST_SCU_FUN_PIN_CTRL5); ++ val &= 0xffffffcf; ++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL5); ++ val = readl(AST_SCU_FUN_PIN_CTRL6); ++ val &= 0xfffffffc; ++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL6); ++ ++ /* SCU reset of PWM module */ ++ val = ast_scu_read(AST_SCU_RESET); ++ val |= SCU_RESET_PWM; ++ ast_scu_write(val, AST_SCU_RESET); ++ val &= ~SCU_RESET_PWM; ++ ast_scu_write(val, AST_SCU_RESET); ++ ++ /* set M, N, and 0 clock regs to 0 */ ++ writel(0, PWM_BASE_ADDR + PWM_M0); ++ writel(0, PWM_BASE_ADDR + PWM_N0); ++ writel(0, PWM_BASE_ADDR + PWM_O0); ++ ++ /* disable fans and tachos, set M type control */ ++ writel(0x1, PWM_BASE_ADDR + PWM_CONTROL); ++ writel(0x1, PWM_BASE_ADDR + PWM_CONTROL_EXT); ++ ++ /* enable pwm channels */ ++ for (chan = 0; chan < PWM_CHANNEL_COUNT; chan++) { ++ uint32_t base = chan < 4 ? PWM_BASE_ADDR : PWM_BASE_ADDR + 0x40; ++ uint8_t ch_duty_shift = 16 * (chan & 0x1); ++ uint8_t ch_pair = (chan & 0x3) / 2; ++ ++ /* enable pwm for the channel */ ++ val = readl(base); ++ val |= ((1 << (chan & 0x3)) << 8); ++ writel(val, base); ++ ++ /* set duty cycle */ ++ val = readl(base + PWM_DUTY_CYCLE + ch_pair * 4); ++ val &= ~(0xffff << ch_duty_shift); ++ val |= (((uint32_t)PWM_DUTY_VALUE) << 8) << ch_duty_shift; ++ writel(val, base + PWM_DUTY_CYCLE + ch_pair * 4); ++ } ++ ++ /* set up clock type M: period = 127 units at 24MHz/8 (resulting ~23kHz period) */ ++ writel(0x7f30, PWM_BASE_ADDR + PWM_CLOCK_SELECTION); ++ ++ /* enable pwm-tacho */ ++ ++ val = readl(PWM_BASE_ADDR + PWM_CONTROL); ++ val |= PWM_CLK_ENABLE; ++ writel(val, PWM_BASE_ADDR + PWM_CONTROL); ++} ++ + extern void espi_init(void); + void ast_g5_intel(void) + { ++ pwm_init(); + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); + sgpio_init(); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch new file mode 100644 index 000000000..91665e064 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch @@ -0,0 +1,91 @@ +From 2078771e0ff84be710250b2e9b2e887f7238f9cc Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Sat, 17 Nov 2018 14:17:27 -0800 +Subject: [PATCH 2/3] Keep interrupts enabled until last second + +The U-Boot bootm command disabled interrupts almost first thing. This +would prevent a person hitting the power button on the host immediatly +after AC on because the BMC would fail to respond to the espi interrupts +and the host would power off. + +Change-Id: I6c0fb5cca1be6c326da4c9a3d3dfbab89dac9928 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + board/aspeed/ast-g5/ast-g5-intel.c | 8 ++++++++ + common/bootm.c | 7 ------- + common/bootm_os.c | 1 + + 3 files changed, 9 insertions(+), 7 deletions(-) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index f810ded4e7..4d399be392 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -263,6 +263,14 @@ int intel_force_firmware_jumper_enabled(void) + return gpio_get_value(GPIO_FF_UPD_JUMPER); + } + ++void arch_preboot_os(void) ++{ ++ // last second before booting... set the LEDs ++ id_led_control(GPIO_ID_LED, EIDLED_On); ++ id_led_control(GPIO_GREEN_LED, EIDLED_On); ++ id_led_control(GPIO_AMBER_LED, EIDLED_Off); ++} ++ + /* PWM offsets */ + + #define PWM_BASE_ADDR 0x1E786000 +diff --git a/common/bootm.c b/common/bootm.c +index 2431019b3f..46909ecdbb 100644 +--- a/common/bootm.c ++++ b/common/bootm.c +@@ -602,7 +602,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int states, bootm_headers_t *images, int boot_progress) + { + boot_os_fn *boot_fn; +- ulong iflag = 0; + int ret = 0, need_boot_fn; + + images->state |= states; +@@ -626,7 +625,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + if (!ret && (states & BOOTM_STATE_LOADOS)) { + ulong load_end; + +- iflag = bootm_disable_interrupts(); + ret = bootm_load_os(images, &load_end, 0); + if (ret == 0) + lmb_reserve(&images->lmb, images->os.load, +@@ -670,8 +668,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP | + BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO); + if (boot_fn == NULL && need_boot_fn) { +- if (iflag) +- enable_interrupts(); + printf("ERROR: booting os '%s' (%d) is not supported\n", + genimg_get_os_name(images->os.os), images->os.os); + bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); +@@ -711,9 +707,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + + /* Deal with any fallout */ + err: +- if (iflag) +- enable_interrupts(); +- + if (ret == BOOTM_ERR_UNIMPLEMENTED) + bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); + else if (ret == BOOTM_ERR_RESET) +diff --git a/common/bootm_os.c b/common/bootm_os.c +index 9ec84bd0db..b56eb39780 100644 +--- a/common/bootm_os.c ++++ b/common/bootm_os.c +@@ -476,6 +476,7 @@ __weak void arch_preboot_os(void) + int boot_selected_os(int argc, char * const argv[], int state, + bootm_headers_t *images, boot_os_fn *boot_fn) + { ++ disable_interrupts(); + arch_preboot_os(); + boot_fn(state, argc, argv, images); + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch new file mode 100644 index 000000000..475b8c3ff --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch @@ -0,0 +1,114 @@ +From a71794fc928429e199c5ea48181e5edfbb0c4f39 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Mon, 19 Nov 2018 11:04:02 -0800 +Subject: [PATCH] Rewrite memmove to optimize on word transfers + +Reading from the flash at boot time was using byte-sized transfers, +which ultimately turns into four word transfers over spi for every real +word read. This change breaks memmove down into a header, body, and +trailer, where the body is all done with word-sized transfers. + +Change-Id: Ie0a1f3261e507fb34a908571883d9bf04a1059ee +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + lib/string.c | 77 +++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 64 insertions(+), 13 deletions(-) + +diff --git a/lib/string.c b/lib/string.c +index 67d5f6a421..0bf472f1f6 100644 +--- a/lib/string.c ++++ b/lib/string.c +@@ -505,26 +505,77 @@ void * memcpy(void *dest, const void *src, size_t count) + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +-void * memmove(void * dest,const void *src,size_t count) ++void *memmove(void *dest, const void *src, size_t count) + { +- char *tmp, *s; +- +- if (src == dest) ++ unsigned char *bdst = (unsigned char *)dest; ++ const unsigned char *bsrc = (const unsigned char *)src; ++ unsigned long *ldst; ++ const unsigned long *lsrc; ++ size_t unaligned_header = 0, unaligned_trailer = 0; ++ size_t unaligned_src = ++ (sizeof(*ldst) - (size_t)src) & (sizeof(*ldst) - 1); ++ size_t unaligned_dst = ++ (sizeof(*ldst) - (size_t)dest) & (sizeof(*ldst) - 1); ++ ++ if (src == dest || !count) + return dest; + ++ if (unaligned_src || unaligned_dst) { ++ if (unaligned_dst != unaligned_src) { ++ unaligned_header = count; ++ } else { ++ unaligned_header = unaligned_src; ++ if (unaligned_header > count) { ++ unaligned_header = count; ++ } ++ } ++ count -= unaligned_header; ++ } ++ if (count & (sizeof(*ldst) - 1)) { ++ unaligned_trailer = count & (sizeof(*ldst) - 1); ++ count -= unaligned_trailer; ++ } ++ + if (dest <= src) { +- tmp = (char *) dest; +- s = (char *) src; +- while (count--) +- *tmp++ = *s++; ++ /* possible un-aligned bytes */ ++ while (unaligned_header--) ++ *bdst++ = *bsrc++; ++ ++ /* aligned words */ ++ ldst = (unsigned long *)bdst; ++ lsrc = (const unsigned long *)bsrc; ++ while (count >= sizeof(*ldst)) { ++ count -= sizeof(*ldst); ++ *ldst++ = *lsrc++; + } +- else { +- tmp = (char *) dest + count; +- s = (char *) src + count; +- while (count--) +- *--tmp = *--s; ++ ++ /* possibly un-aligned bytes */ ++ bdst = (unsigned char *)ldst; ++ bsrc = (const unsigned char *)lsrc; ++ while (unaligned_trailer--) ++ *bdst++ = *bsrc++; ++ } else { ++ bdst += unaligned_header + count + unaligned_trailer; ++ bsrc += unaligned_header + count + unaligned_trailer; ++ ++ /* possibly un-aligned bytes */ ++ while (unaligned_trailer--) ++ *--bdst = *--bsrc; ++ ++ /* aligned words */ ++ ldst = (unsigned long *)bdst; ++ lsrc = (unsigned long *)bsrc; ++ while (count >= sizeof(*ldst)) { ++ count -= sizeof(*ldst); ++ *--ldst = *--lsrc; + } + ++ /* possibly un-aligned bytes */ ++ bdst = (unsigned char *)ldst; ++ bsrc = (const unsigned char *)lsrc; ++ while (unaligned_header--) ++ *--bdst = *--bsrc; ++ } + return dest; + } + #endif +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch new file mode 100644 index 000000000..cc1e56fdb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch @@ -0,0 +1,28 @@ +From 8992df8f3a0f5fc16ec41ad6dd7a5a13e6f94d32 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 5 Dec 2018 16:13:15 -0800 +Subject: [PATCH] Add support for 128MB Macronix spi flash MX66L1G45G + +This will enable u-boot support for the Macronix MX66L1G45G part. + +Change-Id: I5edc69357a8b1607c5c44e53bed3eddf38fdc0be +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + drivers/mtd/spi/sf_params.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c +index c577d9ed6c..d2a96efe48 100644 +--- a/drivers/mtd/spi/sf_params.c ++++ b/drivers/mtd/spi/sf_params.c +@@ -50,6 +50,7 @@ const struct spi_flash_params spi_flash_params_table[] = { + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, + {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP}, + {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP}, ++ {"MX66L1G45G", 0xc2201b, 0x0, 64 * 1024, 2048, RD_FULL, SECT_4K|WR_QPP}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, + #endif + #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch new file mode 100644 index 000000000..b26803c95 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch @@ -0,0 +1,54 @@ +From 8415002a2e77a41831b3064dae264f60996ac88a Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 6 Dec 2018 15:07:09 -0800 +Subject: [PATCH] Enable Macronix and Micron SPI support + +This commit enables Macronix and Micron SPI support. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + configs/ast_g5_ncsi_2boot_defconfig | 2 ++ + configs/ast_g5_ncsi_defconfig | 2 ++ + configs/ast_g5_phy_defconfig | 2 ++ + 3 files changed, 6 insertions(+) + +diff --git a/configs/ast_g5_ncsi_2boot_defconfig b/configs/ast_g5_ncsi_2boot_defconfig +index d5b7894a9e00..abceed817615 100644 +--- a/configs/ast_g5_ncsi_2boot_defconfig ++++ b/configs/ast_g5_ncsi_2boot_defconfig +@@ -10,6 +10,8 @@ CONFIG_FIT_VERBOSE=y + CONFIG_HUSH_PARSER=y + CONFIG_OF_LIBFDT=y + CONFIG_SPI_FLASH=y ++CONFIG_SPI_FLASH_MACRONIX=y ++CONFIG_SPI_FLASH_STMICRO=y + CONFIG_SYS_NS16550=y + CONFIG_FIRMWARE_2ND_BOOT=y + CONFIG_AUTOBOOT=y +diff --git a/configs/ast_g5_ncsi_defconfig b/configs/ast_g5_ncsi_defconfig +index 9481e5fb6e9d..3f504a325649 100644 +--- a/configs/ast_g5_ncsi_defconfig ++++ b/configs/ast_g5_ncsi_defconfig +@@ -10,5 +10,7 @@ CONFIG_FIT_VERBOSE=y + CONFIG_HUSH_PARSER=y + CONFIG_OF_LIBFDT=y + CONFIG_SPI_FLASH=y ++CONFIG_SPI_FLASH_MACRONIX=y ++CONFIG_SPI_FLASH_STMICRO=y + CONFIG_SYS_NS16550=y + CONFIG_USE_IRQ=y +diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig +index 4aefcf49e880..8f0919043376 100644 +--- a/configs/ast_g5_phy_defconfig ++++ b/configs/ast_g5_phy_defconfig +@@ -11,5 +11,7 @@ CONFIG_FIT_VERBOSE=y + CONFIG_HUSH_PARSER=y + CONFIG_OF_LIBFDT=y + CONFIG_SPI_FLASH=y ++CONFIG_SPI_FLASH_MACRONIX=y ++CONFIG_SPI_FLASH_STMICRO=y + CONFIG_SYS_NS16550=y + CONFIG_USE_IRQ=y +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch new file mode 100644 index 000000000..2ed297a96 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch @@ -0,0 +1,73 @@ +From 0039c15251a7fcf60154d59933a11d9e17b04d5c Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 6 Dec 2018 18:49:04 -0800 +Subject: [PATCH] Add support for Macronix and Micron 1Gbits SPI flash + +Quick fix to support Macronix and Micron 1Gbits SPI. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/mach-aspeed/flash.c | 33 ++++++++++++++++++++++++++++++++- + 1 file changed, 32 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-aspeed/flash.c b/arch/arm/mach-aspeed/flash.c +index dece4315d755..2a31b6503a22 100644 +--- a/arch/arm/mach-aspeed/flash.c ++++ b/arch/arm/mach-aspeed/flash.c +@@ -79,6 +79,7 @@ flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* FLASH chips info */ + #define MX25L12805D 0x1820C2 + #define MX25L25635E 0x1920C2 + #define MX66L51235F 0x1A20C2 ++#define MX66L1G45G 0x1B20C2 + #define SST25VF016B 0x4125bf + #define SST25VF064C 0x4b25bf + #define SST25VF040B 0x8d25bf +@@ -978,6 +979,35 @@ static ulong flash_get_size (ulong base, flash_info_t *info) + #endif + break; + ++ case MX66L1G45G: ++ erase_region_size = 0x10000; ++ info->readcmd = 0x0b; ++ info->dualport = 0; ++ info->dummybyte = 1; ++ info->buffersize = 256; ++ WriteClk = 50; ++ EraseClk = 20; ++ ReadClk = 50; ++#if 1 ++ info->sector_count = 2048; ++ info->size = 0x4000000; ++ info->address32 = 1; ++#if defined(CONFIG_FLASH_SPIx2_Dummy) ++ info->readcmd = 0xbb; ++ info->dummybyte = 1; ++ info->dualport = 1; ++ info->iomode = IOMODEx2_dummy; ++#elif defined(CONFIG_FLASH_SPIx4_Dummy) ++ info->readcmd = 0xeb; ++ info->dummybyte = 3; ++ info->dualport = 0; ++ info->iomode = IOMODEx4_dummy; ++ info->quadport = 1; ++ info->dummydata = 0xaa; ++#endif ++#endif ++ break; ++ + case MX25L12805D: + info->sector_count = 256; + info->size = 0x1000000; +@@ -1093,7 +1123,8 @@ static ulong flash_get_size (ulong base, flash_info_t *info) + info->readcmd = 0x0b; + info->dualport = 0; + info->dummybyte = 1; +- info->buffersize = 1; ++ info->buffersize = 256; ++ info->address32 = 1; + WriteClk = 50; + EraseClk = 25; + ReadClk = 50; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch new file mode 100644 index 000000000..1d2b02954 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch @@ -0,0 +1,48 @@ +From bb490aa226dcf261d3d6865be37130765ecbe9f4 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Mon, 17 Dec 2018 20:37:23 -0800 +Subject: [PATCH] u-boot: full platform reset + espi oob-ready + +If the platform is strapped for fast reset, have platform-g5.S do a full +reset and then immediately set oob-ready so the espi master controller +can initiate communication. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + arch/arm/mach-aspeed/platform_g5.S | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-aspeed/platform_g5.S b/arch/arm/mach-aspeed/platform_g5.S +index 2ac1ca4721..66427b6f33 100644 +--- a/arch/arm/mach-aspeed/platform_g5.S ++++ b/arch/arm/mach-aspeed/platform_g5.S +@@ -139,7 +139,7 @@ + But if FW has other initial code executed before platform.S, then it should use WDT_SOC mode. + Use WDT_Full may clear the initial result of prior initial code. + ******************************************************************************/ +-//#define ASTMMC_INIT_RESET_MODE_FULL ++#define ASTMMC_INIT_RESET_MODE_FULL + + /****************************************************************************** + There is a compatibility issue for Hynix DDR4 SDRAM. +@@ -563,6 +563,17 @@ wait_first_reset: + *******************************************/ + + bypass_first_reset: ++ /* Timing from ESPI master requires OOB channel ready bit be set early */ ++ ldr r0, =0x1e6e2070 @ check strapping for eSPI mode ++ tst r0, #0x02000000 @ Test for bit 25 - eSPI Mode ++ beq espi_early_init_done @ if bit 25 clear, dont set OOB ready ++ ++ ldr r0, =0x1e6ee000 ++ ldr r1, [r0] @ ESPI000: ESPI Engine Control Reg ++ orr r1, r1, #0x00000010 @ Set OOB Channel Ready bit ++ str r1, [r0] ++espi_early_init_done: ++ + /* Enable Timer separate clear mode */ + ldr r0, =0x1e782038 + mov r1, #0xAE +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch new file mode 100644 index 000000000..2e541561a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch @@ -0,0 +1,121 @@ +From 06445210bfda7f9bbbb36133e6818575bd6a0cc1 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Tue, 9 Apr 2019 14:42:05 +0800 +Subject: [PATCH] Add system reset status support + +Will display the reset reasons and other CPU information in u-boot, +and save the reset reasons into kernel command line, +for applications to query. + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + arch/arm/include/asm/arch-aspeed/platform.h | 2 ++ + arch/arm/mach-aspeed/ast-scu.c | 4 ++++ + board/aspeed/ast-g5/ast-g5-intel.c | 30 +++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5.c | 7 +++++++ + 4 files changed, 43 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h +index 3b06e52..4e4140d 100644 +--- a/arch/arm/include/asm/arch-aspeed/platform.h ++++ b/arch/arm/include/asm/arch-aspeed/platform.h +@@ -29,6 +29,8 @@ + #include <asm/arch/ast_g5_platform.h> + #include <asm/arch/ast-g5-intel.h> + #define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */ ++#define CONFIG_BOARD_LATE_INIT 1 /* Call board_late_init */ ++#define CONFIG_DISPLAY_CPUINFO 1 + #else + #err "No define for platform.h" + #endif +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index 3a9ba05..976c59b 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -494,6 +494,9 @@ void ast_scu_sys_rest_info(void) + { + u32 rest = ast_scu_read(AST_SCU_SYS_CTRL); + ++#ifdef AST_SOC_G5 ++ printf("RST : 0x%02x\n", rest); ++#else + if (rest & SCU_SYS_EXT_RESET_FLAG) { + printf("RST : External\n"); + ast_scu_write(SCU_SYS_EXT_RESET_FLAG, AST_SCU_SYS_CTRL); +@@ -506,6 +509,7 @@ void ast_scu_sys_rest_info(void) + } else { + printf("RST : CLK en\n"); + } ++#endif + } + + u32 ast_scu_get_vga_memsize(void) +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index bcaf81e..1e8708a 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -303,6 +303,36 @@ static inline void ast_scu_write(uint32_t val, uint32_t reg) + #endif + } + ++void ast_g5_intel_late_init(void) ++{ ++ char *cmdline = NULL; ++ char *cmdline_new = NULL; ++ char buf[32]; ++ u32 rest = 0; ++ ++ /* save and clear reset status */ ++ rest = ast_scu_read(AST_SCU_SYS_CTRL); ++ snprintf(buf, sizeof(buf), " resetreason=0x%x", rest); ++ ast_scu_write(0, AST_SCU_SYS_CTRL); ++ ++ cmdline = getenv("bootargs"); ++ if (!cmdline) { ++ printf("Get bootargs fail!\n"); ++ return; ++ } ++ ++ cmdline_new = malloc(strlen(cmdline) + strlen(buf) + 1); ++ if (!cmdline_new) { ++ printf("Cannot malloc memory!\n"); ++ return; ++ } ++ ++ /* append the reset status into kernel command line */ ++ snprintf(cmdline_new, strlen(cmdline) + strlen(buf) + 1, "%s%s", cmdline, buf); ++ setenv("bootargs", cmdline_new); ++ free(cmdline_new); ++} ++ + static void pwm_init(void) + { + uint32_t val; +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index d41ef9c..0953677 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -19,6 +19,7 @@ + DECLARE_GLOBAL_DATA_PTR; + + extern void ast_g5_intel(void); ++extern void ast_g5_intel_late_init(void); + + int board_early_init_f(void) + { +@@ -40,6 +41,12 @@ int board_init(void) + return 0; + } + ++int board_late_init(void) ++{ ++ ast_g5_intel_late_init(); ++ return 0; ++} ++ + int dram_init(void) + { + u32 vga = ast_scu_get_vga_memsize(); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch new file mode 100644 index 000000000..bdf3d2ddd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch @@ -0,0 +1,38 @@ +From 22c61ba094d8ebdbdcb44f848eef1f5d87a4be87 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 8 Jan 2019 13:33:15 -0800 +Subject: [PATCH] Enable PCIe L1 support + +This commit enables PCIe L1 support using magic registers. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/mach-aspeed/platform_g5.S | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm/mach-aspeed/platform_g5.S b/arch/arm/mach-aspeed/platform_g5.S +index 66427b6f33e7..b4043534b083 100644 +--- a/arch/arm/mach-aspeed/platform_g5.S ++++ b/arch/arm/mach-aspeed/platform_g5.S +@@ -2432,6 +2432,18 @@ spi_cbr_end: + bic r1, r1, #0x00400000 + str r1, [r0] + ++ ldr r0, =0x1e6ed07c @ Enable PCIe L1 support ++ ldr r1, =0xa8 ++ str r1, [r0] ++ ++ ldr r0, =0x1e6ed068 ++ ldr r1, =0xc81f0a ++ str r1, [r0] ++ ++ ldr r0, =0x1e6ed07c ++ mov r1, #0 ++ str r1, [r0] ++ + /****************************************************************************** + Configure MAC timing + ******************************************************************************/ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch new file mode 100755 index 000000000..310d9359b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch @@ -0,0 +1,108 @@ +From c82ba33ea40e0007945cbc93da58f296fdeedeaf Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 11 Feb 2019 15:19:56 +0800 +Subject: [PATCH] Config host uart clock source using environment variable + +In order to support high speed uart for host uarts, +the uart clock needs to be switched between 24M and 192M. +Config SCU4C based on environment variable hostserialcfg, +this variable is set by IPMI OEM commands. + +Tested: +Change the hostserialcfg variable to 0/1/2/3, +using the below commands: + +ipmitool raw 0x32 0x90 1 0; reboot +cat /sys/class/tty/ttyS*/uartclk, all should be 24MHz + +ipmitool raw 0x32 0x90 1 1; reboot +cat /sys/class/tty/ttyS*/uartclk, ttyS0/2/3 should be 192MHz + +ipmitool raw 0x32 0x90 1 2; reboot +cat /sys/class/tty/ttyS*/uartclk, ttyS1 should be 192MHz + +ipmitool raw 0x32 0x90 1 3; reboot +cat /sys/class/tty/ttyS*/uartclk, ttyS0/12/3 should be 192MHz + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + arch/arm/include/asm/arch-aspeed/regs-scu.h | 5 ++++ + board/aspeed/ast-g5/ast-g5-intel.c | 39 +++++++++++++++++++++++++++++ + 2 files changed, 44 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/regs-scu.h b/arch/arm/include/asm/arch-aspeed/regs-scu.h +index 10b983a..8a596ce 100644 +--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h ++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h +@@ -529,6 +529,11 @@ + /* AST_SCU_MAC_CLK 0x48 - MAC interface clock delay setting register */ + + /* AST_SCU_MISC2_CTRL 0x4C - Misc. 2 Control register */ ++#define SCU_UART5_HS_CLOCK (1 << 28) ++#define SCU_UART4_HS_CLOCK (1 << 27) ++#define SCU_UART3_HS_CLOCK (1 << 26) ++#define SCU_UART2_HS_CLOCK (1 << 25) ++#define SCU_UART1_HS_CLOCK (1 << 24) + #ifdef AST_SOC_G5 + #define SCU_PCIE_MAPPING_HIGH (1 << 15) + #define SCU_MALI_DTY_MODE (1 << 8) +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 1e8708a..f810a40 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -103,6 +103,9 @@ static const GPIOValue gpio_table[] = { + #define SGPIO_ENABLE 1 + #define GPIO254 0x254 + ++#define HOST_SERIAL_A_HIGH_SPEED (1 << 0) ++#define HOST_SERIAL_B_HIGH_SPEED (1 << 1) ++ + static void sgpio_init(void) + { + uint32_t value; +@@ -310,6 +313,42 @@ void ast_g5_intel_late_init(void) + char buf[32]; + u32 rest = 0; + ++ /* By default host serail A and B use normal speed */ ++ uint32_t host_serial_cfg = 0; ++ char *host_serial_cfg_txt = NULL; ++ ++ /* Config the uart clock source based on environment configuration */ ++ host_serial_cfg_txt = getenv("hostserialcfg"); ++ ++ if (host_serial_cfg_txt != NULL) ++ host_serial_cfg = simple_strtoul(host_serial_cfg_txt, NULL, 16); ++ ++ if (host_serial_cfg > (HOST_SERIAL_A_HIGH_SPEED | HOST_SERIAL_B_HIGH_SPEED)) { ++ printf("Invalided hostserialcfg %x, use default!\n", host_serial_cfg); ++ host_serial_cfg = 0; ++ } ++ ++ /* SOL implementation requires uart1/uart3/uart4 have the same clock ++ * source for data forwarding, config uart3 and uart4 ++ */ ++ if (host_serial_cfg & HOST_SERIAL_A_HIGH_SPEED) { ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) | ++ SCU_UART1_HS_CLOCK | SCU_UART3_HS_CLOCK | ++ SCU_UART4_HS_CLOCK, AST_SCU_MISC2_CTRL); ++ } else { ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) & ++ ~SCU_UART1_HS_CLOCK & ~SCU_UART3_HS_CLOCK & ++ ~SCU_UART4_HS_CLOCK, AST_SCU_MISC2_CTRL); ++ } ++ ++ if (host_serial_cfg & HOST_SERIAL_B_HIGH_SPEED) { ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) | ++ SCU_UART2_HS_CLOCK, AST_SCU_MISC2_CTRL); ++ } else { ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) & ++ ~SCU_UART2_HS_CLOCK, AST_SCU_MISC2_CTRL); ++ } ++ + /* save and clear reset status */ + rest = ast_scu_read(AST_SCU_SYS_CTRL); + snprintf(buf, sizeof(buf), " resetreason=0x%x", rest); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch new file mode 100644 index 000000000..79028d2a1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch @@ -0,0 +1,620 @@ +From 16209364c27a0cb7e2b7fdd445942f68e9180263 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Wed, 13 Mar 2019 14:28:05 +0530 +Subject: [PATCH] KCS driver support in uBoot + +Added KCS support in uBoot. This will enable +KCS channels and set the specified registers +to do KCS communication in uBoot. It also +consist of read and write KCS message transations +work flow implementation( As specified in IPMI +specification Section 9.15). It is enabled +only when Force Firmware Update Jumper is ON. + +Tested By: +Stopped booting in uBoot and sent IPMI commands +via KCS interfaces using cmdtool.efi. + - Get Device ID: + Req: cmdtool.efi 20 18 1 + Res: 00 23 00 12 03 02 BF 57 01 00 7B 00 00 00 00 00 + - Get Self Test Results + Req: cmdtool.efi 20 18 4 + Res: 00 56 00 + - All other commands + Req: cmdtool.efi 20 18 2 + Res: C1 (Invalid). + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 3 + + board/aspeed/ast-g5/ast-g5-kcs.c | 425 +++++++++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-kcs.h | 114 ++++++++++ + 4 files changed, 543 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-kcs.c + create mode 100644 board/aspeed/ast-g5/ast-g5-kcs.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 9022433..05972b9 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -4,3 +4,4 @@ obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o + obj-y += ast-g5-gpio.o + obj-y += ast-g5-timer.o ++obj-y += ast-g5-kcs.o +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index f810a40..f9955c7 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -437,6 +437,7 @@ static void pwm_init(void) + } + + extern void espi_init(void); ++extern void kcs_init(void); + void ast_g5_intel(void) + { + pwm_init(); +@@ -446,6 +447,8 @@ void ast_g5_intel(void) + timer8_init(); + if (intel_force_firmware_jumper_enabled()) { + id_led_control(GPIO_AMBER_LED, EIDLED_On); ++ kcs_init(); ++ /* TODO: need to stop the booting here. */ + } else { + id_led_control(GPIO_GREEN_LED, EIDLED_On); + } +diff --git a/board/aspeed/ast-g5/ast-g5-kcs.c b/board/aspeed/ast-g5/ast-g5-kcs.c +new file mode 100644 +index 0000000..f983b4a +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-kcs.c +@@ -0,0 +1,425 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "ast-g5-kcs.h" ++ ++#define DEBUG_KCS_ENABLED 0 ++#ifdef DEBUG_KCS_ENABLED ++#define DBG_KCS printf ++#else ++#define DBG_KCS(...) ++#endif ++ ++/* TODO: Move to IPMI file. */ ++#define IPMI_CC_OK 0x00 ++#define IPMI_CC_INVALID 0xC1 ++#define IPMI_CC_UNSPECIFIED 0xFF ++ ++#define KCS_CHANNEL_NO_3 3 ++ ++static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 }; ++ ++static const struct kcs_io_reg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = { ++ { .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 }, ++ { .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 }, ++ { .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 }, ++ { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 } ++}; ++ ++#define NO_OF_ENABLED_KCS_CHANNELS ARRAY_SIZE(enabled_kcs_channel) ++ ++static struct kcs_packet m_kcs_pkt[NO_OF_ENABLED_KCS_CHANNELS]; ++ ++static u16 read_status(u16 channel_num) ++{ ++ return readl(AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].str); ++} ++ ++static void write_status(u16 channel_num, u16 value) ++{ ++ writel(value, AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].str); ++} ++ ++static u16 read_data(u16 channel_num) ++{ ++ return readl(AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].idr); ++} ++ ++static void write_data(u16 channel_num, u16 value) ++{ ++ writel(value, AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].odr); ++} ++ ++static void set_kcs_state(u16 channel_num, u16 state) ++{ ++ u16 status = read_status(channel_num); ++ ++ status &= ~KCS_STATE_MASK; ++ status |= KCS_STATE(state) & KCS_STATE_MASK; ++ write_status(channel_num, status); ++} ++ ++static struct kcs_packet *get_kcs_packet(u16 channel_num) ++{ ++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) { ++ if (channel_num == enabled_kcs_channel[idx]) ++ return &m_kcs_pkt[idx]; ++ } ++ ++ /* very unlike code hits here. */ ++ printf("ERROR: %s error. ChannelNo: %d\n", __func__, channel_num); ++ BUG(); ++} ++ ++static void kcs_force_abort(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ printf("ERROR: KCS communication aborted (Channel:%d, Error:%d)\n", ++ channel_num, kcs_pkt->error); ++ set_kcs_state(channel_num, KCS_STATE_ERROR); ++ read_data(channel_num); ++ write_data(channel_num, ZERO_DATA); ++ ++ kcs_pkt->phase = KCS_PHASE_ERROR; ++ kcs_pkt->read_req_done = false; ++ kcs_pkt->data_in_idx = 0; ++} ++ ++static void init_kcs_packet(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ kcs_pkt->channel = channel_num; ++ kcs_pkt->read_req_done = false; ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ kcs_pkt->error = KCS_NO_ERROR; ++ kcs_pkt->data_in_idx = 0; ++ kcs_pkt->data_out_idx = 0; ++ kcs_pkt->data_out_len = 0; ++} ++ ++static void process_kcs_request(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ if (!kcs_pkt->read_req_done) ++ return; ++ ++ DBG_KCS("%s:- chan:%d\n", __func__, channel_num); ++ ++#ifdef DEBUG_KCS_ENABLED ++ int i; ++ ++ DBG_KCS("Request data(Len:%d): ", kcs_pkt->data_in_idx); ++ for (i = 0; i < kcs_pkt->data_in_idx; i++) ++ DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]); ++ DBG_KCS("\n"); ++#endif ++ ++ /* ++ * TODO: Move it to IPMI Command Handler ++ * Below code is added for timebeing till ++ * we implement the IPMI command handler. ++ */ ++ kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */ ++ kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */ ++ ++ if (((kcs_pkt->data_in[0] >> 2) == 0x06) && ++ (kcs_pkt->data_in[1] == 0x01)) { ++ /* Get Device ID */ ++ u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02, ++ 0xBF, 0x57, 0x01, 0x00, 0x7B, ++ 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ for (i = 0; i < 15; i++) ++ kcs_pkt->data_out[i + 3] = device_id[i]; ++ kcs_pkt->data_out_len = 18; ++ } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) && ++ (kcs_pkt->data_in[1] == 0x04)) { ++ /* Get Self Test Results */ ++ kcs_pkt->data_out[3] = 0x56; ++ kcs_pkt->data_out[4] = 0x00; ++ kcs_pkt->data_out_len = 5; ++ } else { ++ kcs_pkt->data_out[2] = ++ IPMI_CC_INVALID; /* Invalid or not supported. */ ++ kcs_pkt->data_out_len = 3; ++ } ++ /* END: TODO */ ++ ++#ifdef DEBUG_KCS_ENABLED ++ DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len); ++ for (i = 0; i < kcs_pkt->data_out_len; i++) ++ DBG_KCS(" 0x%02x", kcs_pkt->data_out[i]); ++ DBG_KCS("\n"); ++#endif ++ ++ kcs_pkt->phase = KCS_PHASE_READ; ++ write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]); ++ kcs_pkt->read_req_done = false; ++} ++ ++static void read_kcs_data(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ DBG_KCS("%s:- chan:%d, kcs_pkt->phase:%d\n", __func__, channel_num, ++ kcs_pkt->phase); ++ ++ switch (kcs_pkt->phase) { ++ case KCS_PHASE_WRITE_START: ++ kcs_pkt->phase = KCS_PHASE_WRITE_DATA; ++ /* fall through */ ++ ++ case KCS_PHASE_WRITE_DATA: ++ if (kcs_pkt->data_in_idx >= MAX_KCS_PKT_SIZE) { ++ kcs_pkt->error = KCS_LENGTH_ERROR; ++ kcs_force_abort(channel_num); ++ return; ++ } ++ set_kcs_state(channel_num, KCS_STATE_WRITE); ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->data_in[kcs_pkt->data_in_idx++] = ++ read_data(channel_num); ++ break; ++ ++ case KCS_PHASE_WRITE_END: ++ if (kcs_pkt->data_in_idx >= MAX_KCS_PKT_SIZE) { ++ kcs_pkt->error = KCS_LENGTH_ERROR; ++ kcs_force_abort(channel_num); ++ return; ++ } ++ set_kcs_state(channel_num, KCS_STATE_READ); ++ kcs_pkt->data_in[kcs_pkt->data_in_idx++] = ++ read_data(channel_num); ++ kcs_pkt->phase = KCS_PHASE_READ_WAIT; ++ kcs_pkt->read_req_done = true; ++ ++ process_kcs_request(channel_num); ++ break; ++ ++ case KCS_PHASE_READ: ++ if (kcs_pkt->data_out_idx == kcs_pkt->data_out_len) ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ ++ u8 data = read_data(channel_num); ++ if (data != KCS_CTRL_CODE_READ) { ++ DBG_KCS("Invalid Read data. Phase:%d, Data:0x%02x\n", ++ kcs_pkt->phase, data); ++ set_kcs_state(channel_num, KCS_STATE_ERROR); ++ write_data(channel_num, ZERO_DATA); ++ break; ++ } ++ ++ if (kcs_pkt->data_out_idx == kcs_pkt->data_out_len) { ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ break; ++ } ++ write_data(channel_num, ++ kcs_pkt->data_out[kcs_pkt->data_out_idx++]); ++ break; ++ ++ case KCS_PHASE_ABORT_1: ++ set_kcs_state(channel_num, KCS_STATE_READ); ++ read_data(channel_num); ++ write_data(channel_num, kcs_pkt->error); ++ kcs_pkt->phase = KCS_PHASE_ABORT_2; ++ break; ++ ++ case KCS_PHASE_ABORT_2: ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ read_data(channel_num); ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ break; ++ ++ default: ++ kcs_force_abort(channel_num); ++ } ++} ++ ++static void read_kcs_cmd(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ ++ set_kcs_state(channel_num, KCS_STATE_WRITE); ++ write_data(channel_num, ZERO_DATA); ++ ++ u16 cmd = read_data(channel_num); ++ DBG_KCS("%s:- chan:%d, cmd:0x%02x\n", __func__, channel_num, cmd); ++ switch (cmd) { ++ case KCS_CTRL_CODE_WRITE_START: ++ init_kcs_packet(channel_num); ++ kcs_pkt->phase = KCS_PHASE_WRITE_START; ++ break; ++ ++ case KCS_CTRL_CODE_WRITE_END: ++ if (kcs_pkt->error != KCS_NO_ERROR) { ++ kcs_force_abort(channel_num); ++ return; ++ } ++ ++ kcs_pkt->phase = KCS_PHASE_WRITE_END; ++ break; ++ ++ case KCS_CTRL_CODE_GET_STATUS_ABORT: ++ kcs_pkt->phase = KCS_PHASE_ABORT_1; ++ kcs_pkt->error = KCS_ABORT_BY_CMD; ++ break; ++ ++ default: ++ kcs_pkt->error = KCS_ILLEGAL_CTRL_CMD; ++ kcs_force_abort(channel_num); ++ } ++} ++ ++static u16 kcs_irq_handler(struct pt_regs *regs) ++{ ++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) { ++ u16 channel_num = enabled_kcs_channel[idx]; ++ /* Look-up the interrupted KCS channel */ ++ u16 status = read_status(channel_num); ++ if (status & BIT_STATUS_IBF) { ++ if (status & BIT_STATUS_COD) ++ read_kcs_cmd(channel_num); ++ else ++ read_kcs_data(channel_num); ++ } ++ } ++ ++ return 0; ++} ++ ++static void set_kcs_channel_addr(u16 channel_num) ++{ ++ u32 val; ++ ++ switch (channel_num) { ++ case 1: ++ val = readl(AST_LPC_BASE + LPC_HICR4) & ~BIT_LADR12AS; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = (KCS_CHANNEL1_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR12H); ++ val = (KCS_CHANNEL1_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR12L); ++ break; ++ ++ case 2: ++ val = readl(AST_LPC_BASE + LPC_HICR4) | BIT_LADR12AS; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = (KCS_CHANNEL2_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR12H); ++ val = (KCS_CHANNEL2_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR12L); ++ break; ++ ++ case 3: ++ val = (KCS_CHANNEL3_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR3H); ++ val = (KCS_CHANNEL3_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR3L); ++ break; ++ ++ case 4: ++ val = (((KCS_CHANNEL4_ADDR + 1) << 16) | KCS_CHANNEL4_ADDR); ++ writel(val, AST_LPC_BASE + LPC_LADR4); ++ break; ++ ++ default: ++ DBG_KCS("Invalid channel (%d) specified\n", channel_num); ++ break; ++ } ++} ++ ++static void enable_kcs_channel(u16 channel_num, u16 enable) ++{ ++ u32 val; ++ ++ switch (channel_num) { ++ case 1: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE1; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC1E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC1E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE1; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 2: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE2; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC2E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC2E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE2; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 3: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE3; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC3E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR4) | BIT_KCSENBL; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC3E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR4) & ~BIT_KCSENBL; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE3; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 4: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICRB) | BIT_IBFIE4 | ++ BIT_LPC4E; ++ writel(val, AST_LPC_BASE + LPC_HICRB); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICRB) & ++ ~(BIT_IBFIE4 | BIT_LPC4E); ++ writel(val, AST_LPC_BASE + LPC_HICRB); ++ } ++ break; ++ ++ default: ++ DBG_KCS("Invalid channel (%d) specified\n", channel_num); ++ } ++} ++ ++void kcs_init(void) ++{ ++ /* Initialize the KCS channels. */ ++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) { ++ u16 channel_num = enabled_kcs_channel[idx]; ++ DBG_KCS("%s Channel: %d\n", __func__, channel_num); ++ set_kcs_channel_addr(channel_num); ++ enable_kcs_channel(channel_num, 1); ++ ++ /* Set KCS channel state to idle */ ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ } ++ ++ /* KCS interrupt */ ++ request_irq(IRQ_SRC_LPC, kcs_irq_handler); ++} +diff --git a/board/aspeed/ast-g5/ast-g5-kcs.h b/board/aspeed/ast-g5/ast-g5-kcs.h +new file mode 100644 +index 0000000..52b5097 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-kcs.h +@@ -0,0 +1,114 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2018-2019 Intel Corporation */ ++ ++#include <asm/io.h> ++#include <common.h> ++ ++#include "ast-g5.h" ++ ++#define KCS_CHANNEL_MAX 4 ++#define IRQ_SRC_LPC 8 /* IRQ 8 */ ++#define MAX_KCS_PKT_SIZE (64 * 1024) ++/* KCS channel addresses */ ++#define KCS_CHANNEL1_ADDR 0xCA0 ++#define KCS_CHANNEL2_ADDR 0xCA8 ++#define KCS_CHANNEL3_ADDR 0xCA2 ++#define KCS_CHANNEL4_ADDR 0xCB2 ++ ++#define ZERO_DATA 0x00 ++ ++/* Aspeed KCS control registers */ ++#define LPC_HICR0 0x00 /* Host Interface Control Register 0 */ ++#define LPC_HICR1 0x04 /* Host Interface Control Register 1 */ ++#define LPC_HICR2 0x08 /* Host Interface Control Register 2 */ ++#define LPC_HICR3 0x0C /* Host Interface Control Register 3 */ ++#define LPC_HICR4 0x10 /* Host Interface Control Register 4 */ ++#define LPC_LADR3H 0x14 /* LPC channel #3 Address Register H */ ++#define LPC_LADR3L 0x18 /* LPC channel #3 Address Register H */ ++#define LPC_LADR12H 0x1C /* LPC channel #1#2 Address Register H */ ++#define LPC_LADR12L 0x20 /* LPC channel #1#2 Address Register L */ ++#define LPC_IDR1 0x24 /* Input Data Register 1 */ ++#define LPC_IDR2 0x28 /* Input Data Register 2 */ ++#define LPC_IDR3 0x2C /* Input Data Register 3 */ ++#define LPC_ODR1 0x30 /* Output Data Register 1 */ ++#define LPC_ODR2 0x34 /* Output Data Register 2 */ ++#define LPC_ODR3 0x38 /* Output Data Register 3 */ ++#define LPC_STR1 0x3C /* Status Register 1 */ ++#define LPC_STR2 0x40 /* Status Register 2 */ ++#define LPC_STR3 0x44 /* Status Register 3 */ ++ ++/* LPC Bits */ ++#define BIT_LADR12AS BIT(7) /* Channel Address selection */ ++#define BIT_IBFIE1 BIT(1) /* Enable IDR1 Recv completion interrupt */ ++#define BIT_IBFIE2 BIT(2) /* Enable IDR2 Recv completion interrupt */ ++#define BIT_IBFIE3 BIT(3) /* Enable IBF13 interrupt */ ++#define BIT_LPC1E BIT(5) /* Enable LPC channel #1 */ ++#define BIT_LPC2E BIT(6) /* Enable LPC channel #2 */ ++#define BIT_LPC3E BIT(7) /* Enable LPC channel #2 */ ++#define BIT_KCSENBL BIT(2) /* Enable KCS interface in Channel #3 */ ++ ++/* mapped to lpc-host@80 IO space */ ++#define LPC_HICRB 0x080 ++#define BIT_IBFIE4 BIT(1) ++#define BIT_LPC4E BIT(0) ++#define LPC_LADR4 0x090 ++#define LPC_IDR4 0x094 /* Input Data Register 4 */ ++#define LPC_ODR4 0x098 /* Output Data Register 4 */ ++#define LPC_STR4 0x09c /* Status Data Register 4 */ ++ ++#define BIT_STATUS_OBF BIT(0) /* Output Data Register full #1/#2/#3 */ ++#define BIT_STATUS_IBF BIT(1) /* Input Data Register full #1/#2/#3 */ ++#define BIT_STATUS_COD BIT(3) /* Command/Data - (1=command,0=data) */ ++ ++#define KCS_STATE_MASK 0xC0 /* BIT[6:7] of status register */ ++#define KCS_STATE(state) ((state) << 6) ++ ++/* IPMI2.0(section 9.7) - KCS interface State Bits */ ++#define KCS_STATE_IDLE 0x00 ++#define KCS_STATE_READ 0x01 ++#define KCS_STATE_WRITE 0x02 ++#define KCS_STATE_ERROR 0x03 ++ ++/* IPMI2.0(section 9.10) - KCS interface control codes */ ++#define KCS_CTRL_CODE_GET_STATUS_ABORT 0x60 ++#define KCS_CTRL_CODE_WRITE_START 0x61 ++#define KCS_CTRL_CODE_WRITE_END 0x62 ++#define KCS_CTRL_CODE_READ 0x68 ++ ++struct kcs_io_reg { ++ u32 idr; ++ u32 odr; ++ u32 str; ++}; ++ ++enum kcs_phase { ++ KCS_PHASE_IDLE = 0, ++ KCS_PHASE_WRITE_START = 1, ++ KCS_PHASE_WRITE_DATA = 2, ++ KCS_PHASE_WRITE_END = 3, ++ KCS_PHASE_READ_WAIT = 4, ++ KCS_PHASE_READ = 5, ++ KCS_PHASE_ABORT_1 = 6, ++ KCS_PHASE_ABORT_2 = 7, ++ KCS_PHASE_ERROR = 8 ++}; ++ ++enum kcs_error { ++ KCS_NO_ERROR = 0x00, ++ KCS_ABORT_BY_CMD = 0x01, ++ KCS_ILLEGAL_CTRL_CMD = 0x02, ++ KCS_LENGTH_ERROR = 0x06, ++ KCS_UNSPECIFIED_ERROR = 0xFF, ++}; ++ ++struct kcs_packet { ++ enum kcs_phase phase; ++ enum kcs_error error; ++ u16 channel; ++ bool read_req_done; ++ u16 data_in_idx; ++ u8 data_in[MAX_KCS_PKT_SIZE]; ++ u16 data_out_len; ++ u16 data_out_idx; ++ u8 data_out[MAX_KCS_PKT_SIZE]; ++}; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-u-boot-env-change-for-PFR-image.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-u-boot-env-change-for-PFR-image.patch new file mode 100644 index 000000000..746063a56 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-u-boot-env-change-for-PFR-image.patch @@ -0,0 +1,35 @@ +From 6651a2663ee3e9f02c6ed8377097456528a2ee1a Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Tue, 26 Mar 2019 20:34:51 +0530 +Subject: [PATCH] u-boot env change for PFR image + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + include/configs/ast-common.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/configs/ast-common.h b/include/configs/ast-common.h +index b7d7192..dd89d91 100644 +--- a/include/configs/ast-common.h ++++ b/include/configs/ast-common.h +@@ -103,7 +103,7 @@ + #define CONFIG_SYS_MAX_FLASH_BANKS (CONFIG_FMC_CS) + #define CONFIG_SYS_MAX_FLASH_SECT (8192) /* max number of sectors on one chip */ + #define CONFIG_ENV_IS_IN_FLASH 1 +-#define CONFIG_ENV_OFFSET 0x2400000 /* environment starts here */ ++#define CONFIG_ENV_OFFSET 0xa0000 /* environment starts here */ + #define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET) + #define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ + +@@ -111,7 +111,7 @@ + #define CONFIG_ENV_ADDR_REDUND (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET_REDUND) + #define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE + +-#define CONFIG_BOOTCOMMAND "bootm 20080000" ++#define CONFIG_BOOTCOMMAND "bootm 21100000" + #define CONFIG_ENV_OVERWRITE + + #define ASPEED_ENV_SETTINGS \ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0023-Add-TPM-enable-pulse-triggering.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0023-Add-TPM-enable-pulse-triggering.patch new file mode 100644 index 000000000..5e8cd103d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0023-Add-TPM-enable-pulse-triggering.patch @@ -0,0 +1,52 @@ +From f762526077a7af02fc93bacc74fb9d49481d664f Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 29 Mar 2019 12:30:20 -0700 +Subject: [PATCH] Add TPM enable pulse triggering + +This commit adds onboard TPM enable pulse triggering. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + board/aspeed/ast-g5/ast-g5-intel.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index f9955c70d2f2..d9ba4a47a413 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -53,8 +53,8 @@ static const GPIOValue gpio_table[] = { + GPIO_DEBOUNCE_8MS}, + + /* Enable Pulse -- pin D6 */ +- [GPIO_ENABLE_TPM_PULSE] = {PORT_PIN(GPIO_PORT_D, GPIO_PIN_6), +- GPIO_CFG_DEFAULT, 0, GPIO_DEBOUNCE_8MS}, ++ [GPIO_ENABLE_TPM_PULSE] = {TPM_EN_PULSE_PORT_PIN, GPCFG_OUTPUT_EN, 0, ++ GPIO_DEBOUNCE_NONE}, + }; + + #define LPC_SNOOP_ADDR 0x80 +@@ -232,6 +232,13 @@ void id_led_control(int id, int action) + gpio_set_value(s_led_info[id].gpio, s_led_info[id].state); + } + ++static void enable_onboard_tpm(void) ++{ ++ gpio_set_value(GPIO_ENABLE_TPM_PULSE, 1); ++ mdelay(50); ++ gpio_set_value(GPIO_ENABLE_TPM_PULSE, 0); ++} ++ + static void timer8_irq_handler(void *regs) + { + int i; +@@ -445,6 +452,7 @@ void ast_g5_intel(void) + espi_init(); + sgpio_init(); + timer8_init(); ++ enable_onboard_tpm(); + if (intel_force_firmware_jumper_enabled()) { + id_led_control(GPIO_AMBER_LED, EIDLED_On); + kcs_init(); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch new file mode 100644 index 000000000..47cb56062 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch @@ -0,0 +1,339 @@ +From d770ea7a30742339b0692858847838dd2a738aeb Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Fri, 5 Apr 2019 17:53:21 +0530 +Subject: [PATCH] IPMI command handler implementation in uboot + +IPMI command handler implemtation in uBoot. +Implemented IPMI commands: + 1) Get Device ID + 2) Get Self Test Result + +Tested By: +Ran the above IPMI command Via KCS channel +and got proper response. +- Get Device ID + Req: cmdtool.efi 20 18 1 + Res: 0x00 0x23 0x00 0x82 0x03 0x02 0x00 0x57 0x01 0x00 0x7b 0x00 0x00 0x00 0x00 0x00 +- Get Self Test Results + Req: cmdtool.efi 20 18 4 + Res: 00 56 00 + +Change-Id: I18b205bc45c34f7c4ef16adc29fa5bd494624ceb +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-kcs.c | 78 +++++++++++++----------- + board/aspeed/ast-g5/ipmi-handler.c | 118 +++++++++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ipmi-handler.h | 40 +++++++++++++ + 4 files changed, 202 insertions(+), 35 deletions(-) + create mode 100644 board/aspeed/ast-g5/ipmi-handler.c + create mode 100644 board/aspeed/ast-g5/ipmi-handler.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 05972b9..f28fcfe 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -5,3 +5,4 @@ obj-y += ast-g5-irq.o + obj-y += ast-g5-gpio.o + obj-y += ast-g5-timer.o + obj-y += ast-g5-kcs.o ++obj-y += ipmi-handler.o +diff --git a/board/aspeed/ast-g5/ast-g5-kcs.c b/board/aspeed/ast-g5/ast-g5-kcs.c +index f983b4a..05b1cc2 100644 +--- a/board/aspeed/ast-g5/ast-g5-kcs.c ++++ b/board/aspeed/ast-g5/ast-g5-kcs.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + // Copyright (c) 2018-2019 Intel Corporation + +-#include "ast-g5-kcs.h" ++#include "ipmi-handler.h" + + #define DEBUG_KCS_ENABLED 0 + #ifdef DEBUG_KCS_ENABLED +@@ -10,11 +10,6 @@ + #define DBG_KCS(...) + #endif + +-/* TODO: Move to IPMI file. */ +-#define IPMI_CC_OK 0x00 +-#define IPMI_CC_INVALID 0xC1 +-#define IPMI_CC_UNSPECIFIED 0xFF +- + #define KCS_CHANNEL_NO_3 3 + + static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 }; +@@ -104,13 +99,13 @@ static void init_kcs_packet(u16 channel_num) + static void process_kcs_request(u16 channel_num) + { + struct kcs_packet *kcs_pkt = NULL; ++ struct ipmi_cmd_data ipmi_data; + + kcs_pkt = get_kcs_packet(channel_num); + if (!kcs_pkt->read_req_done) + return; + + DBG_KCS("%s:- chan:%d\n", __func__, channel_num); +- + #ifdef DEBUG_KCS_ENABLED + int i; + +@@ -119,37 +114,49 @@ static void process_kcs_request(u16 channel_num) + DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]); + DBG_KCS("\n"); + #endif ++ u8 req_lun = kcs_pkt->data_in[0] & 0x03; /* LUN[1:0] */ ++ ipmi_data.net_fun = (kcs_pkt->data_in[0] >> 2); /* netfn[7:2] */ ++ ipmi_data.cmd = kcs_pkt->data_in[1]; /* cmd */ ++ /* We support only BMC LUN 00h */ ++ if (req_lun != LUN_BMC) { ++ kcs_pkt->data_out[0] = ++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_INVALID_CMD_LUN; /* CC code */ ++ kcs_pkt->data_out_len = 3; ++ goto done; ++ } + +- /* +- * TODO: Move it to IPMI Command Handler +- * Below code is added for timebeing till +- * we implement the IPMI command handler. +- */ +- kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */ +- kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */ +- kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */ +- +- if (((kcs_pkt->data_in[0] >> 2) == 0x06) && +- (kcs_pkt->data_in[1] == 0x01)) { +- /* Get Device ID */ +- u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02, +- 0xBF, 0x57, 0x01, 0x00, 0x7B, +- 0x00, 0x00, 0x00, 0x00, 0x00 }; +- for (i = 0; i < 15; i++) +- kcs_pkt->data_out[i + 3] = device_id[i]; +- kcs_pkt->data_out_len = 18; +- } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) && +- (kcs_pkt->data_in[1] == 0x04)) { +- /* Get Self Test Results */ +- kcs_pkt->data_out[3] = 0x56; +- kcs_pkt->data_out[4] = 0x00; +- kcs_pkt->data_out_len = 5; +- } else { +- kcs_pkt->data_out[2] = +- IPMI_CC_INVALID; /* Invalid or not supported. */ ++ /* Boundary check */ ++ if ((kcs_pkt->data_in_idx - 2) > sizeof(ipmi_data.req_data)) { ++ kcs_pkt->data_out[0] = ++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_OUT_OF_SPACE; /* CC code */ + kcs_pkt->data_out_len = 3; ++ goto done; + } +- /* END: TODO */ ++ /* Fill in IPMI request data */ ++ ipmi_data.req_len = kcs_pkt->data_in_idx - 2; ++ for (i = 0; i < kcs_pkt->data_in_idx - 2; i++) ++ ipmi_data.req_data[i] = kcs_pkt->data_in[i + 2]; ++ ++ /* Call IPMI command handler */ ++ ipmi_cmd_handler(&ipmi_data); ++ ++ /* Get IPMI response and fill KCS out data */ ++ /* First 2 bytes in KCS response are netFn, Cmd */ ++ kcs_pkt->data_out[0] = GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; ++ if ((ipmi_data.res_len + 2) > sizeof(kcs_pkt->data_out)) { ++ kcs_pkt->data_out[2] = IPMI_CC_UNSPECIFIED; /* CC code */ ++ kcs_pkt->data_out_len = 3; ++ goto done; ++ } ++ for (i = 0; i < ipmi_data.res_len; i++) ++ kcs_pkt->data_out[i + 2] = ipmi_data.res_data[i]; ++ ++ kcs_pkt->data_out_len = ipmi_data.res_len + 2; + + #ifdef DEBUG_KCS_ENABLED + DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len); +@@ -158,6 +165,7 @@ static void process_kcs_request(u16 channel_num) + DBG_KCS("\n"); + #endif + ++done: + kcs_pkt->phase = KCS_PHASE_READ; + write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]); + kcs_pkt->read_req_done = false; +diff --git a/board/aspeed/ast-g5/ipmi-handler.c b/board/aspeed/ast-g5/ipmi-handler.c +new file mode 100644 +index 0000000..9cccee9 +--- /dev/null ++++ b/board/aspeed/ast-g5/ipmi-handler.c +@@ -0,0 +1,118 @@ ++ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "ipmi-handler.h" ++ ++/* IPMI network function codes */ ++#define NETFN_APP 0x06 ++ ++/* IPMI command codes */ ++#define CMD_GET_DEV_ID 0x01 ++#define CMD_GET_SELF_TEST_RESULTS 0x04 ++ ++typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res); ++ ++struct get_dev_id { ++ u8 completion_code; ++ u8 dev_id; ++ u8 dev_rev; ++ u8 fw_rev1; ++ u8 fw_rev2; ++ u8 ipmi_ver; ++ u8 dev_support; ++ u8 mfg_id[3]; ++ u8 product_id[2]; ++ u8 aux_fw_rev[4]; ++}; ++struct self_test_res { ++ u8 completion_code; ++ u8 res_byte[2]; ++}; ++ ++struct ipmi_cmd_table { ++ u8 net_fun; ++ u8 cmd; ++ fun_handler process_cmd; ++}; ++ ++static u16 get_device_id(u8 *req, u16 req_len, u8 *res) ++{ ++ /* Get Device ID */ ++ bool operation = 1; /* Firmware operation */ ++ u8 intel_mfg_id[3] = { 0x57, 0x01, 0x00 }; ++ u8 platform_id[2] = { 0x7B, 0x00 }; ++ u8 aux_fw_rev[4] = { 0x00, 0x00, 0x00, 0x00 }; ++ struct get_dev_id *result = (struct get_dev_id *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ result->dev_id = 0x23; ++ result->dev_rev = 0x00; /* Not provides dev SDR */ ++ ++ result->ipmi_ver = 0x02; /* IPMI 2.0 */ ++ result->dev_support = 0x00; /* No dev support in this mode */ ++ memcpy(result->mfg_id, intel_mfg_id, sizeof(result->mfg_id)); ++ memcpy(result->aux_fw_rev, aux_fw_rev, sizeof(result->aux_fw_rev)); ++ ++ /* TODO: Get Firmware version from flash(PFM Header) */ ++ result->fw_rev1 = ((operation << 7) | (0x02 & 0x7F)); ++ result->fw_rev2 = 0x03; ++ /* TODO: Read Platform ID from GPIO */ ++ memcpy(result->product_id, platform_id, sizeof(result->product_id)); ++ ++ return sizeof(struct get_dev_id); ++} ++ ++static u16 get_self_test_result(u8 *req, u16 req_len, u8 *res) ++{ ++ /* Get Self Test Results */ ++ struct self_test_res *result = (struct self_test_res *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ result->res_byte[0] = 0x56; /* Self test function not implemented. */ ++ result->res_byte[1] = 0x00; ++ ++ return sizeof(struct self_test_res); ++} ++ ++const struct ipmi_cmd_table cmd_info[] = { ++ { NETFN_APP, CMD_GET_DEV_ID, get_device_id }, ++ { NETFN_APP, CMD_GET_SELF_TEST_RESULTS, get_self_test_result } ++}; ++ ++#define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info) ++ ++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data) ++{ ++ int i = 0; ++ for (i = 0; i < CMD_TABLE_SIZE; i++) { ++ if ((cmd_info[i].net_fun == ipmi_data->net_fun) && ++ (cmd_info[i].cmd == ipmi_data->cmd)) { ++ break; ++ } ++ } ++ ++ if (i == CMD_TABLE_SIZE) { ++ /* Invalid or not supported. */ ++ ipmi_data->res_data[0] = IPMI_CC_INVALID_CMD; ++ ipmi_data->res_len = 1; ++ return; ++ } ++ ++ /* Call the appropriate function handler */ ++ ipmi_data->res_len = ++ cmd_info[i].process_cmd(ipmi_data->req_data, ipmi_data->req_len, ++ &ipmi_data->res_data[0]); ++ ++ return; ++} +diff --git a/board/aspeed/ast-g5/ipmi-handler.h b/board/aspeed/ast-g5/ipmi-handler.h +new file mode 100644 +index 0000000..9d46d9b +--- /dev/null ++++ b/board/aspeed/ast-g5/ipmi-handler.h +@@ -0,0 +1,40 @@ ++ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2018-2019 Intel Corporation */ ++ ++#include "ast-g5-kcs.h" ++ ++/* IPMI completion codes */ ++#define IPMI_CC_OK 0x00 ++#define IPMI_CC_NODE_BUSY 0xC0 ++#define IPMI_CC_INVALID_CMD 0xC1 ++#define IPMI_CC_INVALID_CMD_LUN 0xC2 ++#define IPMI_CC_OUT_OF_SPACE 0xC4 ++#define IPMI_CC_INVALID_DATA_LENGTH 0xC7 ++#define IPMI_CC_INVALID_DATA_FIELD 0xCC ++#define IPMI_CC_UNSPECIFIED 0xFF ++ ++/* BMC IPMB LUNs */ ++#define LUN_BMC 0x00 ++#define LUN_OEM1 0x01 ++#define LUN_SMS 0x02 ++#define LUN_OEM2 0x01 ++ ++ ++#define MAX_IPMI_REQ_DATA_SIZE MAX_KCS_PKT_SIZE ++#define MAX_IPMI_RES_DATA_SIZE 64 ++ ++/* Response netFn[7:2], Lun[1:0] */ ++#define GET_RESP_NETFN_LUN(lun, netfn) \ ++ ((lun & 0x03) | (((netfn + 1) << 2) & 0xFD)) ++ ++struct ipmi_cmd_data { ++ u8 net_fun; ++ u8 cmd; ++ u16 req_len; ++ u16 res_len; ++ u8 req_data[MAX_IPMI_REQ_DATA_SIZE]; ++ u8 res_data[MAX_IPMI_RES_DATA_SIZE]; ++}; ++ ++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0025-Manufacturing-mode-physical-presence-detection.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0025-Manufacturing-mode-physical-presence-detection.patch new file mode 100644 index 000000000..f6f402bc9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0025-Manufacturing-mode-physical-presence-detection.patch @@ -0,0 +1,121 @@ +From 6b4e1b3672433c0d7d392404e19d114ae25e0eb2 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Wed, 24 Apr 2019 22:35:43 +0530 +Subject: [PATCH] Manufacturing mode physical presence detection + +Support for physical presence of manufacturing mode added. +Front panel power button press for 8 seconds will be detected +and marked as special mode for manufacturing request + +Tested: +1. Verified by holding the power button when u-boot boots for +8 seconds, and confirmed that bootargs passed to linux has +special=mfg string +2. Verified in normal condition special=mfg string is not passed. + +Change-Id: Id7e7c7e7860c7ef3ae8e3a7a7cfda7ff506c0f2b +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + board/aspeed/ast-g5/ast-g5-gpio.h | 2 +- + board/aspeed/ast-g5/ast-g5-intel.c | 39 ++++++++++++++++++++++++++++++++++++-- + 2 files changed, 38 insertions(+), 3 deletions(-) + +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.h b/board/aspeed/ast-g5/ast-g5-gpio.h +index a820c0f..ed2499f 100644 +--- a/board/aspeed/ast-g5/ast-g5-gpio.h ++++ b/board/aspeed/ast-g5/ast-g5-gpio.h +@@ -72,7 +72,7 @@ + #define AMB_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_5) + #define FORCE_BMC_UPDATE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_0) + #define TPM_EN_PULSE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_6) +- ++#define FP_PWR_BTN_PORT_PIN PORT_PIN(GPIO_PORT_E, GPIO_PIN_2) + + // GPIO Configuration Register bits + #define GPCFG_EVENT_TO_SMI (1 << 7) // 1 == enabled +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 881ab89..86b422f 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -24,6 +24,7 @@ enum gpio_names { + GPIO_AMBER_LED, + GPIO_FF_UPD_JUMPER, + GPIO_ENABLE_TPM_PULSE, ++ GPIO_FP_PWR_BTN, + }; + + #define GPIO_CFG_DEFAULT (GPCFG_ACTIVE_HIGH | GPCFG_LEVEL_TRIG) +@@ -55,6 +56,10 @@ static const GPIOValue gpio_table[] = { + /* Enable Pulse -- pin D6 */ + [GPIO_ENABLE_TPM_PULSE] = {TPM_EN_PULSE_PORT_PIN, GPCFG_OUTPUT_EN, 0, + GPIO_DEBOUNCE_NONE}, ++ /* Front Panel Power Button -- pin E2 */ ++ [GPIO_FP_PWR_BTN] = {FP_PWR_BTN_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ + }; + + #define LPC_SNOOP_ADDR 0x80 +@@ -313,12 +318,35 @@ static inline void ast_scu_write(uint32_t val, uint32_t reg) + #endif + } + ++static bool is_mfg_mode_phy_req(void) ++{ ++ /* ++ * Assume mfg mode physical request is made, if power button ++ * is pressed continously for 8 seconds, indicate the ++ * same in bootargs ++ */ ++ const uint32_t delay_in_ms = 100; ++ const uint32_t read_count = ((8 * 1000) / delay_in_ms); ++ for (uint32_t count = 0; count < read_count; ++count) { ++ if (!gpio_get_value(GPIO_FP_PWR_BTN)) ++ return false; ++ ++ mdelay(delay_in_ms); ++ } ++ debug("is_mfg_mode_phy_req : detected mfg mode request\n"); ++ ++ return true; ++} ++ + void ast_g5_intel_late_init(void) + { + char *cmdline = NULL; + char *cmdline_new = NULL; + char buf[32]; + u32 rest = 0; ++ const char *special_mfg_str = " special=mfg"; ++ const u32 special_str_size = strlen(special_mfg_str); ++ u32 buf_count = 0; + + /* By default host serail A and B use normal speed */ + uint32_t host_serial_cfg = 0; +@@ -367,14 +395,21 @@ void ast_g5_intel_late_init(void) + return; + } + +- cmdline_new = malloc(strlen(cmdline) + strlen(buf) + 1); ++ cmdline_new = malloc(strlen(cmdline) + strlen(buf) + ++ special_str_size + 1); + if (!cmdline_new) { + printf("Cannot malloc memory!\n"); + return; + } + + /* append the reset status into kernel command line */ +- snprintf(cmdline_new, strlen(cmdline) + strlen(buf) + 1, "%s%s", cmdline, buf); ++ buf_count = snprintf(cmdline_new, strlen(cmdline) + strlen(buf) + 1, ++ "%s%s", cmdline, buf); ++ ++ if (is_mfg_mode_phy_req()) ++ snprintf(cmdline_new + buf_count - 1, special_str_size + 1, ++ "%s", special_mfg_str); ++ + setenv("bootargs", cmdline_new); + free(cmdline_new); + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0026-Aspeed-I2C-support-in-U-Boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0026-Aspeed-I2C-support-in-U-Boot.patch new file mode 100644 index 000000000..950763d8e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0026-Aspeed-I2C-support-in-U-Boot.patch @@ -0,0 +1,1520 @@ +From a1626519109c9bda02119114224f3759add21f00 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 6 May 2019 03:01:55 +0530 +Subject: [PATCH] Aspeed I2C support in U-Boot + +Adding Aspeed I2C support in u-boot and enabled +i2c command. It is mainly used for PFR to +communicate with PFR CPLD while BMC is in +"Force Firmware Update" mode. + +Tested: +Using i2c command in u-boot, validated +i2c functionalities like probe, read and write. + +Change-Id: Iad9af4a57a58bc8dc5c470bfadad9dac1371c238 +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + arch/arm/include/asm/arch-aspeed/ast_g5_platform.h | 14 + + arch/arm/include/asm/arch-aspeed/ast_scu.h | 5 + + arch/arm/include/asm/arch-aspeed/regs-iic.h | 204 +++++ + arch/arm/mach-aspeed/ast-scu.c | 122 +++ + board/aspeed/ast-g5/ast-g5.c | 8 + + configs/ast_g5_phy_defconfig | 2 + + drivers/i2c/Kconfig | 5 + + drivers/i2c/Makefile | 1 + + drivers/i2c/ast_i2c.c | 849 +++++++++++++++++++++ + drivers/i2c/ast_i2c.h | 131 ++++ + include/configs/ast-common.h | 5 + + 11 files changed, 1346 insertions(+) + create mode 100644 arch/arm/include/asm/arch-aspeed/regs-iic.h + create mode 100644 drivers/i2c/ast_i2c.c + create mode 100644 drivers/i2c/ast_i2c.h + +diff --git a/arch/arm/include/asm/arch-aspeed/ast_g5_platform.h b/arch/arm/include/asm/arch-aspeed/ast_g5_platform.h +index 4210873..a84f471 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast_g5_platform.h ++++ b/arch/arm/include/asm/arch-aspeed/ast_g5_platform.h +@@ -105,6 +105,20 @@ + #define AST_LPC_BASE 0x1E789000 /* LPC */ + #define AST_MBX_BASE 0x1E789200 /* Mailbox */ + #define AST_I2C_BASE 0x1E78A000 /* I2C */ ++#define AST_I2C_DEV0_BASE 0x1E78A040 /* I2C DEV1 */ ++#define AST_I2C_DEV1_BASE 0x1E78A080 /* I2C DEV2 */ ++#define AST_I2C_DEV2_BASE 0x1E78A0C0 /* I2C DEV3 */ ++#define AST_I2C_DEV3_BASE 0x1E78A100 /* I2C DEV4 */ ++#define AST_I2C_DEV4_BASE 0x1E78A140 /* I2C DEV5 */ ++#define AST_I2C_DEV5_BASE 0x1E78A180 /* I2C DEV6 */ ++#define AST_I2C_DEV6_BASE 0x1E78A1C0 /* I2C DEV7 */ ++#define AST_I2C_DEV7_BASE 0x1E78A300 /* I2C DEV8 */ ++#define AST_I2C_DEV8_BASE 0x1E78A340 /* I2C DEV9 */ ++#define AST_I2C_DEV9_BASE 0x1E78A380 /* I2C DEV10 */ ++#define AST_I2C_DEV10_BASE 0x1E78A3C0 /* I2C DEV11 */ ++#define AST_I2C_DEV11_BASE 0x1E78A400 /* I2C DEV12 */ ++#define AST_I2C_DEV12_BASE 0x1E78A440 /* I2C DEV13 */ ++#define AST_I2C_DEV13_BASE 0x1E78A480 /* I2C DEV14 */ + #define AST_PECI_BASE 0x1E78B000 /* PECI */ + #define AST_PCIARBITER_BASE 0x1E78C000 /* PCI ARBITER */ + #define AST_UART2_BASE 0x1E78D000 /* UART2 */ +diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h +index 369c4e3..b94d13e 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h ++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h +@@ -28,6 +28,8 @@ + #ifndef __AST_SCU_H + #define __AST_SCU_H + ++#include <common.h> ++ + extern void ast_scu_show_system_info (void); + extern void ast_scu_sys_rest_info(void); + extern void ast_scu_security_info(void); +@@ -39,13 +41,16 @@ extern u32 ast_get_clk_source(void); + extern u32 ast_get_h_pll_clk(void); + extern u32 ast_get_m_pll_clk(void); + extern u32 ast_get_ahbclk(void); ++extern u32 ast_get_pclk(void); + + extern u32 ast_scu_get_vga_memsize(void); + ++extern void ast_scu_init_i2c(void); + extern void ast_scu_init_eth(u8 num); + extern void ast_scu_multi_func_eth(u8 num); + extern void ast_scu_multi_func_romcs(u8 num); + extern void ast_scu_multi_func_sgpio(void); ++extern void ast_scu_multi_func_i2c(u8 bus_no); + + void ast_config_uart5_clk(void); + +diff --git a/arch/arm/include/asm/arch-aspeed/regs-iic.h b/arch/arm/include/asm/arch-aspeed/regs-iic.h +new file mode 100644 +index 0000000..2847430 +--- /dev/null ++++ b/arch/arm/include/asm/arch-aspeed/regs-iic.h +@@ -0,0 +1,204 @@ ++/* arch/arm/plat-aspeed/include/mach/regs-iic.h ++ * ++ * Copyright (c) 2012 ASPEED Technology Inc. <ryan_chen@aspeedtech.com> ++ * http://www.aspeedtech.com/ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * ASPEED I2C Controller ++*/ ++ ++#ifndef __ASM_ARCH_REGS_IIC_H ++#define __ASM_ARCH_REGS_IIC_H __FILE__ ++ ++#ifdef CONFIG_ARCH_AST1010 ++#define AST_I2C_DMA_SIZE 512 ++#else ++#define AST_I2C_DMA_SIZE 4096 ++#endif ++#define AST_I2C_PAGE_SIZE 256 ++ ++#if defined(CONFIG_ARCH_AST2300) ++#define NUM_BUS 9 ++#elif defined(CONFIG_ARCH_AST2400) ++#define NUM_BUS 14 ++#elif defined(CONFIG_ARCH_AST1010) ++#define NUM_BUS 15 ++#elif defined(CONFIG_ARCH_AST1520) || defined(CONFIG_ARCH_AST3200) || defined(CONFIG_ARCH_AST2500) ++#define NUM_BUS 14 ++#elif defined(CONFIG_ARCH_AST1220) ++#define NUM_BUS 10 ++#else ++#err "NO define NUM_BUS" ++#endif ++ ++/* I2C Register */ ++#define I2C_FUN_CTRL_REG 0x00 ++#define I2C_AC_TIMING_REG1 0x04 ++#define I2C_AC_TIMING_REG2 0x08 ++#define I2C_INTR_CTRL_REG 0x0c ++#define I2C_INTR_STS_REG 0x10 ++#define I2C_CMD_REG 0x14 ++#define I2C_DEV_ADDR_REG 0x18 ++#define I2C_BUF_CTRL_REG 0x1c ++#define I2C_BYTE_BUF_REG 0x20 ++#define I2C_DMA_BASE_REG 0x24 ++#define I2C_DMA_LEN_REG 0x28 ++ ++ ++/* Gloable Register Definition */ ++/* 0x00 : I2C Interrupt Status Register */ ++/* 0x08 : I2C Interrupt Target Assignment */ ++#if defined(CONFIG_ARCH_AST2400) ++#define AST_I2CG_INTR14 (0x1 << 13) ++#define AST_I2CG_INTR13 (0x1 << 12) ++#define AST_I2CG_INTR12 (0x1 << 11) ++#define AST_I2CG_INTR11 (0x1 << 10) ++#define AST_I2CG_INTR10 (0x1 << 9) ++#elif defined(CONFIG_ARCH_AST1010) ++#define AST_I2CG_INTR14 (0x1 << 13) ++#define AST_I2CG_INTR13 (0x1 << 12) ++#define AST_I2CG_INTR12 (0x1 << 11) ++#define AST_I2CG_INTR11 (0x1 << 10) ++#define AST_I2CG_INTR10 (0x1 << 9) ++#endif ++#define AST_I2CG_INTR09 (0x1 << 8) ++#define AST_I2CG_INTR08 (0x1 << 7) ++#define AST_I2CG_INTR07 (0x1 << 6) ++#define AST_I2CG_INTR06 (0x1 << 5) ++#define AST_I2CG_INTR05 (0x1 << 4) ++#define AST_I2CG_INTR04 (0x1 << 3) ++#define AST_I2CG_INTR03 (0x1 << 2) ++#define AST_I2CG_INTR02 (0x1 << 1) ++#define AST_I2CG_INTR01 (0x1 ) ++ ++/* Device Register Definition */ ++/* 0x00 : I2CD Function Control Register */ ++#define AST_I2CD_BUFF_SEL_MASK (0x7 << 20) ++#define AST_I2CD_BUFF_SEL(x) (x << 20) // page 0 ~ 7 ++#define AST_I2CD_M_SDA_LOCK_EN (0x1 << 16) ++#define AST_I2CD_MULTI_MASTER_DIS (0x1 << 15) ++#define AST_I2CD_M_SCL_DRIVE_EN (0x1 << 14) ++#define AST_I2CD_MSB_STS (0x1 << 9) ++#define AST_I2CD_SDA_DRIVE_1T_EN (0x1 << 8) ++#define AST_I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7) ++#define AST_I2CD_M_HIGH_SPEED_EN (0x1 << 6) ++#define AST_I2CD_DEF_ADDR_EN (0x1 << 5) ++#define AST_I2CD_DEF_ALERT_EN (0x1 << 4) ++#define AST_I2CD_DEF_ARP_EN (0x1 << 3) ++#define AST_I2CD_DEF_GCALL_EN (0x1 << 2) ++#define AST_I2CD_SLAVE_EN (0x1 << 1) ++#define AST_I2CD_MASTER_EN (0x1 ) ++ ++/* 0x04 : I2CD Clock and AC Timing Control Register #1 */ ++#define AST_I2CD_tBUF (0x1 << 28) // 0~7 ++#define AST_I2CD_tHDSTA (0x1 << 24) // 0~7 ++#define AST_I2CD_tACST (0x1 << 20) // 0~7 ++#define AST_I2CD_tCKHIGH (0x1 << 16) // 0~7 ++#define AST_I2CD_tCKLOW (0x1 << 12) // 0~7 ++#define AST_I2CD_tHDDAT (0x1 << 10) // 0~7 ++#define AST_I2CD_CLK_TO_BASE_DIV (0x1 << 8) // 0~3 ++#define AST_I2CD_CLK_BASE_DIV (0x1 ) // 0~0xf ++ ++/* 0x08 : I2CD Clock and AC Timing Control Register #2 */ ++#define AST_I2CD_tTIMEOUT (0x1 ) // 0~7 ++#define AST_NO_TIMEOUT_CTRL 0x0 ++ ++ ++/* 0x0c : I2CD Interrupt Control Register */ ++#define AST_I2CD_SDA_DL_TO_INTR_EN (0x1 << 14) ++#define AST_I2CD_BUS_RECOVER_INTR_EN (0x1 << 13) ++#define AST_I2CD_SMBUS_ALT_INTR_EN (0x1 << 12) ++#define AST_I2CD_SLAVE_MATCH_INTR_EN (0x1 << 7) ++#define AST_I2CD_SCL_TO_INTR_EN (0x1 << 6) ++#define AST_I2CD_ABNORMAL_INTR_EN (0x1 << 5) ++#define AST_I2CD_NORMAL_STOP_INTR_EN (0x1 << 4) ++#define AST_I2CD_ARBIT_LOSS_INTR_EN (0x1 << 3) ++#define AST_I2CD_RX_DOWN_INTR_EN (0x1 << 2) ++#define AST_I2CD_TX_NAK_INTR_EN (0x1 << 1) ++#define AST_I2CD_TX_ACK_INTR_EN (0x1 ) ++ ++/* 0x10 : I2CD Interrupt Status Register : WC */ ++#define AST_I2CD_INTR_STS_SDA_DL_TO (0x1 << 14) ++#define AST_I2CD_INTR_STS_BUS_RECOVER (0x1 << 13) ++#define AST_I2CD_INTR_STS_SMBUS_ALT (0x1 << 12) ++#define AST_I2CD_INTR_STS_SMBUS_ARP_ADDR (0x1 << 11) ++#define AST_I2CD_INTR_STS_SMBUS_DEV_ALT (0x1 << 10) ++#define AST_I2CD_INTR_STS_SMBUS_DEF_ADDR (0x1 << 9) ++#define AST_I2CD_INTR_STS_GCALL_ADDR (0x1 << 8) ++#define AST_I2CD_INTR_STS_SLAVE_MATCH (0x1 << 7) ++#define AST_I2CD_INTR_STS_SCL_TO (0x1 << 6) ++#define AST_I2CD_INTR_STS_ABNORMAL (0x1 << 5) ++#define AST_I2CD_INTR_STS_NORMAL_STOP (0x1 << 4) ++#define AST_I2CD_INTR_STS_ARBIT_LOSS (0x1 << 3) ++#define AST_I2CD_INTR_STS_RX_DOWN (0x1 << 2) ++#define AST_I2CD_INTR_STS_TX_NAK (0x1 << 1) ++#define AST_I2CD_INTR_STS_TX_ACK (0x1 ) ++ ++/* 0x14 : I2CD Command/Status Register */ ++#define AST_I2CD_SDA_OE (0x1 << 28) ++#define AST_I2CD_SDA_O (0x1 << 27) ++#define AST_I2CD_SCL_OE (0x1 << 26) ++#define AST_I2CD_SCL_O (0x1 << 25) ++#define AST_I2CD_TX_TIMING (0x1 << 24) // 0 ~3 ++#define AST_I2CD_TX_STATUS (0x1 << 23) ++// Tx State Machine ++#define AST_I2CD_IDLE 0x0 ++#define AST_I2CD_MACTIVE 0x8 ++#define AST_I2CD_MSTART 0x9 ++#define AST_I2CD_MSTARTR 0xa ++#define AST_I2CD_MSTOP 0xb ++#define AST_I2CD_MTXD 0xc ++#define AST_I2CD_MRXACK 0xd ++#define AST_I2CD_MRXD 0xe ++#define AST_I2CD_MTXACK 0xf ++#define AST_I2CD_SWAIT 0x1 ++#define AST_I2CD_SRXD 0x4 ++#define AST_I2CD_STXACK 0x5 ++#define AST_I2CD_STXD 0x6 ++#define AST_I2CD_SRXACK 0x7 ++#define AST_I2CD_RECOVER 0x3 ++ ++#define AST_I2CD_SCL_LINE_STS (0x1 << 18) ++#define AST_I2CD_SDA_LINE_STS (0x1 << 17) ++#define AST_I2CD_BUS_BUSY_STS (0x1 << 16) ++#define AST_I2CD_SDA_OE_OUT_DIR (0x1 << 15) ++#define AST_I2CD_SDA_O_OUT_DIR (0x1 << 14) ++#define AST_I2CD_SCL_OE_OUT_DIR (0x1 << 13) ++#define AST_I2CD_SCL_O_OUT_DIR (0x1 << 12) ++#define AST_I2CD_BUS_RECOVER_CMD_EN (0x1 << 11) ++#define AST_I2CD_S_ALT_EN (0x1 << 10) ++// 0 : DMA Buffer, 1: Pool Buffer ++//AST1070 DMA register ++#define AST_I2CD_RX_DMA_ENABLE (0x1 << 9) ++#define AST_I2CD_TX_DMA_ENABLE (0x1 << 8) ++ ++/* Command Bit */ ++#define AST_I2CD_RX_BUFF_ENABLE (0x1 << 7) ++#define AST_I2CD_TX_BUFF_ENABLE (0x1 << 6) ++#define AST_I2CD_M_STOP_CMD (0x1 << 5) ++#define AST_I2CD_M_S_RX_CMD_LAST (0x1 << 4) ++#define AST_I2CD_M_RX_CMD (0x1 << 3) ++#define AST_I2CD_S_TX_CMD (0x1 << 2) ++#define AST_I2CD_M_TX_CMD (0x1 << 1) ++#define AST_I2CD_M_START_CMD (0x1 ) ++ ++/* 0x18 : I2CD Slave Device Address Register */ ++ ++/* 0x1C : I2CD Pool Buffer Control Register */ ++#define AST_I2CD_RX_BUF_ADDR_GET(x) ((x>> 24)& 0xff) ++#define AST_I2CD_RX_BUF_END_ADDR_SET(x) (x << 16) ++#define AST_I2CD_TX_DATA_BUF_END_SET(x) ((x&0xff) << 8) ++#define AST_I2CD_TX_DATA_BUF_GET(x) ((x >>8) & 0xff) ++#define AST_I2CD_BUF_BASE_ADDR_SET(x) (x & 0x3f) ++ ++/* 0x20 : I2CD Transmit/Receive Byte Buffer Register */ ++#define AST_I2CD_GET_MODE(x) ((x >> 8) & 0x1) ++ ++#define AST_I2CD_RX_BYTE_BUFFER (0xff << 8) ++#define AST_I2CD_TX_BYTE_BUFFER (0xff ) ++ ++ ++#endif /* __ASM_ARCH_REGS_IIC_H */ +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index 976c59b..7e8d4c8 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -112,6 +112,12 @@ static struct soc_id soc_map_table[] = { + SOC_ID("AST2530-A2", 0x04030403), + }; + ++void ast_scu_init_i2c(void) ++{ ++ ast_scu_write(ast_scu_read(AST_SCU_RESET) & ~SCU_RESET_I2C, ++ AST_SCU_RESET); ++} ++ + void ast_scu_init_eth(u8 num) + { + /* Set MAC delay Timing */ +@@ -292,6 +298,23 @@ u32 ast_get_ahbclk(void) + return ((hpll / axi_div) / ahb_div); + } + ++u32 ast_get_pclk(void) ++{ ++ unsigned int div, hpll; ++ ++ hpll = ast_get_h_pll_clk(); ++ div = SCU_GET_PCLK_DIV(ast_scu_read(AST_SCU_CLK_SEL)); ++#ifdef AST_SOC_G5 ++ div = (div+1) << 2; ++#else ++ div = (div+1) << 1; ++#endif ++ ++ debug("HPLL=%d, Div=%d, PCLK=%d\n", hpll, div, hpll/div); ++ return (hpll/div); ++} ++ ++ + #else /* ! AST_SOC_G5 */ + + u32 ast_get_h_pll_clk(void) +@@ -457,6 +480,105 @@ void ast_scu_multi_func_sgpio(void) + AST_SCU_FUN_PIN_CTRL2); + } + ++extern void ast_scu_multi_func_i2c(u8 bus_no) ++{ ++#ifdef CONFIG_ARCH_AST1010 ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL4) | ++ SCU_FUN_PIN_SCL13 | ++ SCU_FUN_PIN_SDA13 | ++ SCU_FUN_PIN_SCL14 | ++ SCU_FUN_PIN_SDA14, ++ AST_SCU_FUN_PIN_CTRL4); ++ ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL2) | ++ SCU_FUN_PIN_SCL1 | ++ SCU_FUN_PIN_SDA1 | ++ SCU_FUN_PIN_SCL2 | ++ SCU_FUN_PIN_SDA2 | ++ SCU_FUN_PIN_SCL3 | ++ SCU_FUN_PIN_SDA3 | ++ SCU_FUN_PIN_SCL4 | ++ SCU_FUN_PIN_SDA4 | ++ SCU_FUN_PIN_SCL5 | ++ SCU_FUN_PIN_SDA5 | ++ SCU_FUN_PIN_SCL6 | ++ SCU_FUN_PIN_SDA6 | ++ SCU_FUN_PIN_SCL7 | ++ SCU_FUN_PIN_SDA7 | ++ SCU_FUN_PIN_SCL8 | ++ SCU_FUN_PIN_SDA8 | ++ SCU_FUN_PIN_SALT1 | ++ SCU_FUN_PIN_SALT2 | ++ SCU_FUN_PIN_SALT3 | ++ SCU_FUN_PIN_SALT4, ++ AST_SCU_FUN_PIN_CTRL2); ++ ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) | ++ SCU_FUN_PIN_SCL9 | ++ SCU_FUN_PIN_SDA9 | ++ SCU_FUN_PIN_SCL10 | ++ SCU_FUN_PIN_SDA10 | ++ SCU_FUN_PIN_SCL11 | ++ SCU_FUN_PIN_SDA11 | ++ SCU_FUN_PIN_SCL12 | ++ SCU_FUN_PIN_SDA12, ++ AST_SCU_FUN_PIN_CTRL1); ++#else ++ //TODO check ... //In AST2400 Due to share pin with SD , please not enable I2C 10 ~14 ++ // AST 2400 have 14 , AST 2300 9 ... ++ u32 pin_ctrl = ast_scu_read(AST_SCU_FUN_PIN_CTRL5); ++ switch (bus_no) { ++ case 0: ++ break; ++ case 1: ++ break; ++ case 2: ++ pin_ctrl |= SCU_FUC_PIN_I2C3; ++ break; ++ case 3: ++ pin_ctrl |= SCU_FUC_PIN_I2C4; ++ break; ++ case 4: ++ pin_ctrl |= SCU_FUC_PIN_I2C5; ++ break; ++ case 5: ++ pin_ctrl |= SCU_FUC_PIN_I2C6; ++ break; ++ case 6: ++ pin_ctrl |= SCU_FUC_PIN_I2C7; ++ break; ++ case 7: ++ pin_ctrl |= SCU_FUC_PIN_I2C8; ++ break; ++ case 8: ++ pin_ctrl |= SCU_FUC_PIN_I2C9; ++ break; ++ case 9: ++ pin_ctrl |= SCU_FUC_PIN_I2C10; ++ pin_ctrl &= ~SCU_FUC_PIN_SD1; ++ break; ++ case 10: ++ pin_ctrl |= SCU_FUC_PIN_I2C11; ++ pin_ctrl &= ~SCU_FUC_PIN_SD1; ++ break; ++ case 11: ++ pin_ctrl |= SCU_FUC_PIN_I2C12; ++ pin_ctrl &= ~SCU_FUC_PIN_SD1; ++ break; ++ case 12: ++ pin_ctrl |= SCU_FUC_PIN_I2C13; ++ pin_ctrl &= ~SCU_FUC_PIN_SD1; ++ break; ++ case 13: ++ pin_ctrl |= SCU_FUC_PIN_I2C14; ++ break; ++ } ++ ++ ast_scu_write(pin_ctrl, AST_SCU_FUN_PIN_CTRL5); ++#endif ++} ++ ++ + u32 ast_scu_revision_id(void) + { + int i; +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index 0953677..7309589 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -13,6 +13,7 @@ + #include <asm/arch/ast_scu.h> + #include <asm/arch/ast-sdmc.h> + #include <asm/io.h> ++#include <i2c.h> + + #include "ast-g5.h" + +@@ -37,6 +38,13 @@ int board_init(void) + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; + gd->flags = 0; + ++ /* Initialize I2C */ ++#if defined(CONFIG_SYS_I2C) ++ i2c_init(I2C_ADAP->speed, I2C_ADAP->slaveaddr); ++#else ++ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); ++#endif ++ + ast_g5_intel(); + return 0; + } +diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig +index 8f09190..47d9563 100644 +--- a/configs/ast_g5_phy_defconfig ++++ b/configs/ast_g5_phy_defconfig +@@ -15,3 +15,5 @@ CONFIG_SPI_FLASH_MACRONIX=y + CONFIG_SPI_FLASH_STMICRO=y + CONFIG_SYS_NS16550=y + CONFIG_USE_IRQ=y ++CONFIG_CMD_I2C=y ++CONFIG_SYS_I2C_AST=y +diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig +index 6e22bba..5368ba2 100644 +--- a/drivers/i2c/Kconfig ++++ b/drivers/i2c/Kconfig +@@ -58,6 +58,11 @@ config DM_I2C_GPIO + bindings are supported. + Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt + ++config SYS_I2C_AST ++ bool "Aspeed I2C bus driver" ++ help ++ Add support for Aspeed I2C busses on AST2500 processors. ++ + config SYS_I2C_FSL + bool "Freescale I2C bus driver" + depends on DM_I2C +diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile +index 167424d..b2a69ea 100644 +--- a/drivers/i2c/Makefile ++++ b/drivers/i2c/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o + obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o + + obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o ++obj-$(CONFIG_SYS_I2C_AST) += ast_i2c.o + obj-$(CONFIG_I2C_MV) += mv_i2c.o + obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o + obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o +diff --git a/drivers/i2c/ast_i2c.c b/drivers/i2c/ast_i2c.c +new file mode 100644 +index 0000000..0b12fc2 +--- /dev/null ++++ b/drivers/i2c/ast_i2c.c +@@ -0,0 +1,849 @@ ++/* ++ * i2c_adap_ast.c ++ * ++ * I2C adapter for the ASPEED I2C bus access. ++ * ++ * Copyright (C) 2012-2020 ASPEED Technology Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * 2012.07.26: Initial version [Ryan Chen] ++ */ ++ ++#include <common.h> ++#include <configs/ast-common.h> ++#include <fdtdec.h> ++ ++#include <asm/arch/ast_scu.h> ++#include <i2c.h> ++ ++#include <asm/arch/regs-iic.h> ++#include <asm/io.h> ++ ++// AST2400 buffer mode issue , force I2C slave write use byte mode , read use ++// buffer mode ++/* Use platform_data instead of module parameters */ ++/* Fast Mode = 400 kHz, Standard = 100 kHz */ ++// static int clock = 100; /* Default: 100 kHz */ ++ ++/***************************************************************************/ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#define I2C_TIMEOUT_COUNT 200 ++#define I2C_SLEEP_US 1000 ++ ++static unsigned int i2c_bus_num __attribute__((section(".data"))); ++ ++/* Information about i2c controller */ ++struct ast_i2c_bus { ++ u32 reg_base; /* virtual */ ++ u32 speed; ++ u32 state; /* I2C xfer mode state matchine */ ++ u16 addr; /* slave address */ ++ u16 flags; ++ u16 a_len; /* msg length */ ++ u8 *a_buf; /* pointer to msg data */ ++ u16 d_len; /* msg length */ ++ u8 *d_buf; /* pointer to msg data */ ++}; ++ ++static struct ast_i2c_bus ast_i2c[NUM_BUS] __attribute__((section(".data"))); ++ ++struct ast_i2c_timing_table { ++ u32 divisor; ++ u32 timing; ++}; ++ ++static struct ast_i2c_timing_table i2c_timing_table[] = { ++#if defined(AST_SOC_G5) ++ /* Divisor : Base Clock : tCK High : tCK Low */ ++ /* Divisor : [3:0] : [19:16]: [15:12] */ ++ { 6, 0x77700300 | (0x0) | (0x2 << 16) | (0x2 << 12) }, ++ { 7, 0x77700300 | (0x0) | (0x3 << 16) | (0x2 << 12) }, ++ { 8, 0x77700300 | (0x0) | (0x3 << 16) | (0x3 << 12) }, ++ { 9, 0x77700300 | (0x0) | (0x4 << 16) | (0x3 << 12) }, ++ { 10, 0x77700300 | (0x0) | (0x4 << 16) | (0x4 << 12) }, ++ { 11, 0x77700300 | (0x0) | (0x5 << 16) | (0x4 << 12) }, ++ { 12, 0x77700300 | (0x0) | (0x5 << 16) | (0x5 << 12) }, ++ { 13, 0x77700300 | (0x0) | (0x6 << 16) | (0x5 << 12) }, ++ { 14, 0x77700300 | (0x0) | (0x6 << 16) | (0x6 << 12) }, ++ { 15, 0x77700300 | (0x0) | (0x7 << 16) | (0x6 << 12) }, ++ { 16, 0x77700300 | (0x0) | (0x7 << 16) | (0x7 << 12) }, ++ { 17, 0x77700300 | (0x0) | (0x8 << 16) | (0x7 << 12) }, ++ { 18, 0x77700300 | (0x0) | (0x8 << 16) | (0x8 << 12) }, ++ { 19, 0x77700300 | (0x0) | (0x9 << 16) | (0x8 << 12) }, ++ { 20, 0x77700300 | (0x0) | (0x9 << 16) | (0x9 << 12) }, ++ { 21, 0x77700300 | (0x0) | (0xa << 16) | (0x9 << 12) }, ++ { 22, 0x77700300 | (0x0) | (0xa << 16) | (0xa << 12) }, ++ { 23, 0x77700300 | (0x0) | (0xb << 16) | (0xa << 12) }, ++ { 24, 0x77700300 | (0x0) | (0xb << 16) | (0xb << 12) }, ++ { 25, 0x77700300 | (0x0) | (0xc << 16) | (0xb << 12) }, ++ { 26, 0x77700300 | (0x0) | (0xc << 16) | (0xc << 12) }, ++ { 27, 0x77700300 | (0x0) | (0xd << 16) | (0xc << 12) }, ++ { 28, 0x77700300 | (0x0) | (0xd << 16) | (0xd << 12) }, ++ { 29, 0x77700300 | (0x0) | (0xe << 16) | (0xd << 12) }, ++ { 30, 0x77700300 | (0x0) | (0xe << 16) | (0xe << 12) }, ++ { 31, 0x77700300 | (0x0) | (0xf << 16) | (0xe << 12) }, ++ { 32, 0x77700300 | (0x0) | (0xf << 16) | (0xf << 12) }, ++ ++ { 34, 0x77700300 | (0x1) | (0x8 << 16) | (0x7 << 12) }, ++ { 36, 0x77700300 | (0x1) | (0x8 << 16) | (0x8 << 12) }, ++ { 38, 0x77700300 | (0x1) | (0x9 << 16) | (0x8 << 12) }, ++ { 40, 0x77700300 | (0x1) | (0x9 << 16) | (0x9 << 12) }, ++ { 42, 0x77700300 | (0x1) | (0xa << 16) | (0x9 << 12) }, ++ { 44, 0x77700300 | (0x1) | (0xa << 16) | (0xa << 12) }, ++ { 46, 0x77700300 | (0x1) | (0xb << 16) | (0xa << 12) }, ++ { 48, 0x77700300 | (0x1) | (0xb << 16) | (0xb << 12) }, ++ { 50, 0x77700300 | (0x1) | (0xc << 16) | (0xb << 12) }, ++ { 52, 0x77700300 | (0x1) | (0xc << 16) | (0xc << 12) }, ++ { 54, 0x77700300 | (0x1) | (0xd << 16) | (0xc << 12) }, ++ { 56, 0x77700300 | (0x1) | (0xd << 16) | (0xd << 12) }, ++ { 58, 0x77700300 | (0x1) | (0xe << 16) | (0xd << 12) }, ++ { 60, 0x77700300 | (0x1) | (0xe << 16) | (0xe << 12) }, ++ { 62, 0x77700300 | (0x1) | (0xf << 16) | (0xe << 12) }, ++ { 64, 0x77700300 | (0x1) | (0xf << 16) | (0xf << 12) }, ++ ++ { 68, 0x77700300 | (0x2) | (0x8 << 16) | (0x7 << 12) }, ++ { 72, 0x77700300 | (0x2) | (0x8 << 16) | (0x8 << 12) }, ++ { 76, 0x77700300 | (0x2) | (0x9 << 16) | (0x8 << 12) }, ++ { 80, 0x77700300 | (0x2) | (0x9 << 16) | (0x9 << 12) }, ++ { 84, 0x77700300 | (0x2) | (0xa << 16) | (0x9 << 12) }, ++ { 88, 0x77700300 | (0x2) | (0xa << 16) | (0xa << 12) }, ++ { 92, 0x77700300 | (0x2) | (0xb << 16) | (0xa << 12) }, ++ { 96, 0x77700300 | (0x2) | (0xb << 16) | (0xb << 12) }, ++ { 100, 0x77700300 | (0x2) | (0xc << 16) | (0xb << 12) }, ++ { 104, 0x77700300 | (0x2) | (0xc << 16) | (0xc << 12) }, ++ { 108, 0x77700300 | (0x2) | (0xd << 16) | (0xc << 12) }, ++ { 112, 0x77700300 | (0x2) | (0xd << 16) | (0xd << 12) }, ++ { 116, 0x77700300 | (0x2) | (0xe << 16) | (0xd << 12) }, ++ { 120, 0x77700300 | (0x2) | (0xe << 16) | (0xe << 12) }, ++ { 124, 0x77700300 | (0x2) | (0xf << 16) | (0xe << 12) }, ++ { 128, 0x77700300 | (0x2) | (0xf << 16) | (0xf << 12) }, ++ ++ { 136, 0x77700300 | (0x3) | (0x8 << 16) | (0x7 << 12) }, ++ { 144, 0x77700300 | (0x3) | (0x8 << 16) | (0x8 << 12) }, ++ { 152, 0x77700300 | (0x3) | (0x9 << 16) | (0x8 << 12) }, ++ { 160, 0x77700300 | (0x3) | (0x9 << 16) | (0x9 << 12) }, ++ { 168, 0x77700300 | (0x3) | (0xa << 16) | (0x9 << 12) }, ++ { 176, 0x77700300 | (0x3) | (0xa << 16) | (0xa << 12) }, ++ { 184, 0x77700300 | (0x3) | (0xb << 16) | (0xa << 12) }, ++ { 192, 0x77700300 | (0x3) | (0xb << 16) | (0xb << 12) }, ++ { 200, 0x77700300 | (0x3) | (0xc << 16) | (0xb << 12) }, ++ { 208, 0x77700300 | (0x3) | (0xc << 16) | (0xc << 12) }, ++ { 216, 0x77700300 | (0x3) | (0xd << 16) | (0xc << 12) }, ++ { 224, 0x77700300 | (0x3) | (0xd << 16) | (0xd << 12) }, ++ { 232, 0x77700300 | (0x3) | (0xe << 16) | (0xd << 12) }, ++ { 240, 0x77700300 | (0x3) | (0xe << 16) | (0xe << 12) }, ++ { 248, 0x77700300 | (0x3) | (0xf << 16) | (0xe << 12) }, ++ { 256, 0x77700300 | (0x3) | (0xf << 16) | (0xf << 12) }, ++ ++ { 272, 0x77700300 | (0x4) | (0x8 << 16) | (0x7 << 12) }, ++ { 288, 0x77700300 | (0x4) | (0x8 << 16) | (0x8 << 12) }, ++ { 304, 0x77700300 | (0x4) | (0x9 << 16) | (0x8 << 12) }, ++ { 320, 0x77700300 | (0x4) | (0x9 << 16) | (0x9 << 12) }, ++ { 336, 0x77700300 | (0x4) | (0xa << 16) | (0x9 << 12) }, ++ { 352, 0x77700300 | (0x4) | (0xa << 16) | (0xa << 12) }, ++ { 368, 0x77700300 | (0x4) | (0xb << 16) | (0xa << 12) }, ++ { 384, 0x77700300 | (0x4) | (0xb << 16) | (0xb << 12) }, ++ { 400, 0x77700300 | (0x4) | (0xc << 16) | (0xb << 12) }, ++ { 416, 0x77700300 | (0x4) | (0xc << 16) | (0xc << 12) }, ++ { 432, 0x77700300 | (0x4) | (0xd << 16) | (0xc << 12) }, ++ { 448, 0x77700300 | (0x4) | (0xd << 16) | (0xd << 12) }, ++ { 464, 0x77700300 | (0x4) | (0xe << 16) | (0xd << 12) }, ++ { 480, 0x77700300 | (0x4) | (0xe << 16) | (0xe << 12) }, ++ { 496, 0x77700300 | (0x4) | (0xf << 16) | (0xe << 12) }, ++ { 512, 0x77700300 | (0x4) | (0xf << 16) | (0xf << 12) }, ++ ++ { 544, 0x77700300 | (0x5) | (0x8 << 16) | (0x7 << 12) }, ++ { 576, 0x77700300 | (0x5) | (0x8 << 16) | (0x8 << 12) }, ++ { 608, 0x77700300 | (0x5) | (0x9 << 16) | (0x8 << 12) }, ++ { 640, 0x77700300 | (0x5) | (0x9 << 16) | (0x9 << 12) }, ++ { 672, 0x77700300 | (0x5) | (0xa << 16) | (0x9 << 12) }, ++ { 704, 0x77700300 | (0x5) | (0xa << 16) | (0xa << 12) }, ++ { 736, 0x77700300 | (0x5) | (0xb << 16) | (0xa << 12) }, ++ { 768, 0x77700300 | (0x5) | (0xb << 16) | (0xb << 12) }, ++ { 800, 0x77700300 | (0x5) | (0xc << 16) | (0xb << 12) }, ++ { 832, 0x77700300 | (0x5) | (0xc << 16) | (0xc << 12) }, ++ { 864, 0x77700300 | (0x5) | (0xd << 16) | (0xc << 12) }, ++ { 896, 0x77700300 | (0x5) | (0xd << 16) | (0xd << 12) }, ++ { 928, 0x77700300 | (0x5) | (0xe << 16) | (0xd << 12) }, ++ { 960, 0x77700300 | (0x5) | (0xe << 16) | (0xe << 12) }, ++ { 992, 0x77700300 | (0x5) | (0xf << 16) | (0xe << 12) }, ++ { 1024, 0x77700300 | (0x5) | (0xf << 16) | (0xf << 12) }, ++ ++ { 1088, 0x77700300 | (0x6) | (0x8 << 16) | (0x7 << 12) }, ++ { 1152, 0x77700300 | (0x6) | (0x8 << 16) | (0x8 << 12) }, ++ { 1216, 0x77700300 | (0x6) | (0x9 << 16) | (0x8 << 12) }, ++ { 1280, 0x77700300 | (0x6) | (0x9 << 16) | (0x9 << 12) }, ++ { 1344, 0x77700300 | (0x6) | (0xa << 16) | (0x9 << 12) }, ++ { 1408, 0x77700300 | (0x6) | (0xa << 16) | (0xa << 12) }, ++ { 1472, 0x77700300 | (0x6) | (0xb << 16) | (0xa << 12) }, ++ { 1536, 0x77700300 | (0x6) | (0xb << 16) | (0xb << 12) }, ++ { 1600, 0x77700300 | (0x6) | (0xc << 16) | (0xb << 12) }, ++ { 1664, 0x77700300 | (0x6) | (0xc << 16) | (0xc << 12) }, ++ { 1728, 0x77700300 | (0x6) | (0xd << 16) | (0xc << 12) }, ++ { 1792, 0x77700300 | (0x6) | (0xd << 16) | (0xd << 12) }, ++ { 1856, 0x77700300 | (0x6) | (0xe << 16) | (0xd << 12) }, ++ { 1920, 0x77700300 | (0x6) | (0xe << 16) | (0xe << 12) }, ++ { 1984, 0x77700300 | (0x6) | (0xf << 16) | (0xe << 12) }, ++ { 2048, 0x77700300 | (0x6) | (0xf << 16) | (0xf << 12) }, ++ ++ { 2176, 0x77700300 | (0x7) | (0x8 << 16) | (0x7 << 12) }, ++ { 2304, 0x77700300 | (0x7) | (0x8 << 16) | (0x8 << 12) }, ++ { 2432, 0x77700300 | (0x7) | (0x9 << 16) | (0x8 << 12) }, ++ { 2560, 0x77700300 | (0x7) | (0x9 << 16) | (0x9 << 12) }, ++ { 2688, 0x77700300 | (0x7) | (0xa << 16) | (0x9 << 12) }, ++ { 2816, 0x77700300 | (0x7) | (0xa << 16) | (0xa << 12) }, ++ { 2944, 0x77700300 | (0x7) | (0xb << 16) | (0xa << 12) }, ++ { 3072, 0x77700300 | (0x7) | (0xb << 16) | (0xb << 12) }, ++#else ++ /* Divisor : [3:0] : [18:16]: [13:12] */ ++ { 6, 0x77700300 | (0x0) | (0x2 << 16) | (0x2 << 12) }, ++ { 7, 0x77700300 | (0x0) | (0x3 << 16) | (0x2 << 12) }, ++ { 8, 0x77700300 | (0x0) | (0x3 << 16) | (0x3 << 12) }, ++ { 9, 0x77700300 | (0x0) | (0x4 << 16) | (0x3 << 12) }, ++ { 10, 0x77700300 | (0x0) | (0x4 << 16) | (0x4 << 12) }, ++ { 11, 0x77700300 | (0x0) | (0x5 << 16) | (0x4 << 12) }, ++ { 12, 0x77700300 | (0x0) | (0x5 << 16) | (0x5 << 12) }, ++ { 13, 0x77700300 | (0x0) | (0x6 << 16) | (0x5 << 12) }, ++ { 14, 0x77700300 | (0x0) | (0x6 << 16) | (0x6 << 12) }, ++ { 15, 0x77700300 | (0x0) | (0x7 << 16) | (0x6 << 12) }, ++ { 16, 0x77700300 | (0x0) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 18, 0x77700300 | (0x1) | (0x4 << 16) | (0x3 << 12) }, ++ { 20, 0x77700300 | (0x1) | (0x4 << 16) | (0x4 << 12) }, ++ { 22, 0x77700300 | (0x1) | (0x5 << 16) | (0x4 << 12) }, ++ { 24, 0x77700300 | (0x1) | (0x5 << 16) | (0x5 << 12) }, ++ { 26, 0x77700300 | (0x1) | (0x6 << 16) | (0x5 << 12) }, ++ { 28, 0x77700300 | (0x1) | (0x6 << 16) | (0x6 << 12) }, ++ { 30, 0x77700300 | (0x1) | (0x7 << 16) | (0x6 << 12) }, ++ { 32, 0x77700300 | (0x1) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 36, 0x77700300 | (0x2) | (0x4 << 16) | (0x3 << 12) }, ++ { 40, 0x77700300 | (0x2) | (0x4 << 16) | (0x4 << 12) }, ++ { 44, 0x77700300 | (0x2) | (0x5 << 16) | (0x4 << 12) }, ++ { 48, 0x77700300 | (0x2) | (0x5 << 16) | (0x5 << 12) }, ++ { 52, 0x77700300 | (0x2) | (0x6 << 16) | (0x5 << 12) }, ++ { 56, 0x77700300 | (0x2) | (0x6 << 16) | (0x6 << 12) }, ++ { 60, 0x77700300 | (0x2) | (0x7 << 16) | (0x6 << 12) }, ++ { 64, 0x77700300 | (0x2) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 72, 0x77700300 | (0x3) | (0x4 << 16) | (0x3 << 12) }, ++ { 80, 0x77700300 | (0x3) | (0x4 << 16) | (0x4 << 12) }, ++ { 88, 0x77700300 | (0x3) | (0x5 << 16) | (0x4 << 12) }, ++ { 96, 0x77700300 | (0x3) | (0x5 << 16) | (0x5 << 12) }, ++ { 104, 0x77700300 | (0x3) | (0x6 << 16) | (0x5 << 12) }, ++ { 112, 0x77700300 | (0x3) | (0x6 << 16) | (0x6 << 12) }, ++ { 120, 0x77700300 | (0x3) | (0x7 << 16) | (0x6 << 12) }, ++ { 128, 0x77700300 | (0x3) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 144, 0x77700300 | (0x4) | (0x4 << 16) | (0x3 << 12) }, ++ { 160, 0x77700300 | (0x4) | (0x4 << 16) | (0x4 << 12) }, ++ { 176, 0x77700300 | (0x4) | (0x5 << 16) | (0x4 << 12) }, ++ { 192, 0x77700300 | (0x4) | (0x5 << 16) | (0x5 << 12) }, ++ { 208, 0x77700300 | (0x4) | (0x6 << 16) | (0x5 << 12) }, ++ { 224, 0x77700300 | (0x4) | (0x6 << 16) | (0x6 << 12) }, ++ { 240, 0x77700300 | (0x4) | (0x7 << 16) | (0x6 << 12) }, ++ { 256, 0x77700300 | (0x4) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 288, 0x77700300 | (0x5) | (0x4 << 16) | (0x3 << 12) }, ++ { 320, 0x77700300 | (0x5) | (0x4 << 16) | (0x4 << 12) }, ++ { 352, 0x77700300 | (0x5) | (0x5 << 16) | (0x4 << 12) }, ++ { 384, 0x77700300 | (0x5) | (0x5 << 16) | (0x5 << 12) }, ++ { 416, 0x77700300 | (0x5) | (0x6 << 16) | (0x5 << 12) }, ++ { 448, 0x77700300 | (0x5) | (0x6 << 16) | (0x6 << 12) }, ++ { 480, 0x77700300 | (0x5) | (0x7 << 16) | (0x6 << 12) }, ++ { 512, 0x77700300 | (0x5) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 576, 0x77700300 | (0x6) | (0x4 << 16) | (0x3 << 12) }, ++ { 640, 0x77700300 | (0x6) | (0x4 << 16) | (0x4 << 12) }, ++ { 704, 0x77700300 | (0x6) | (0x5 << 16) | (0x4 << 12) }, ++ { 768, 0x77700300 | (0x6) | (0x5 << 16) | (0x5 << 12) }, ++ { 832, 0x77700300 | (0x6) | (0x6 << 16) | (0x5 << 12) }, ++ { 896, 0x77700300 | (0x6) | (0x6 << 16) | (0x6 << 12) }, ++ { 960, 0x77700300 | (0x6) | (0x7 << 16) | (0x6 << 12) }, ++ { 1024, 0x77700300 | (0x6) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 1152, 0x77700300 | (0x7) | (0x4 << 16) | (0x3 << 12) }, ++ { 1280, 0x77700300 | (0x7) | (0x4 << 16) | (0x4 << 12) }, ++ { 1408, 0x77700300 | (0x7) | (0x5 << 16) | (0x4 << 12) }, ++ { 1536, 0x77700300 | (0x7) | (0x5 << 16) | (0x5 << 12) }, ++ { 1664, 0x77700300 | (0x7) | (0x6 << 16) | (0x5 << 12) }, ++ { 1792, 0x77700300 | (0x7) | (0x6 << 16) | (0x6 << 12) }, ++ { 1920, 0x77700300 | (0x7) | (0x7 << 16) | (0x6 << 12) }, ++ { 2048, 0x77700300 | (0x7) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 2304, 0x77700300 | (0x8) | (0x4 << 16) | (0x3 << 12) }, ++ { 2560, 0x77700300 | (0x8) | (0x4 << 16) | (0x4 << 12) }, ++ { 2816, 0x77700300 | (0x8) | (0x5 << 16) | (0x4 << 12) }, ++ { 3072, 0x77700300 | (0x8) | (0x5 << 16) | (0x5 << 12) }, ++ { 3328, 0x77700300 | (0x8) | (0x6 << 16) | (0x5 << 12) }, ++ { 3584, 0x77700300 | (0x8) | (0x6 << 16) | (0x6 << 12) }, ++ { 3840, 0x77700300 | (0x8) | (0x7 << 16) | (0x6 << 12) }, ++ { 4096, 0x77700300 | (0x8) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 4608, 0x77700300 | (0x9) | (0x4 << 16) | (0x3 << 12) }, ++ { 5120, 0x77700300 | (0x9) | (0x4 << 16) | (0x4 << 12) }, ++ { 5632, 0x77700300 | (0x9) | (0x5 << 16) | (0x4 << 12) }, ++ { 6144, 0x77700300 | (0x9) | (0x5 << 16) | (0x5 << 12) }, ++ { 6656, 0x77700300 | (0x9) | (0x6 << 16) | (0x5 << 12) }, ++ { 7168, 0x77700300 | (0x9) | (0x6 << 16) | (0x6 << 12) }, ++ { 7680, 0x77700300 | (0x9) | (0x7 << 16) | (0x6 << 12) }, ++ { 8192, 0x77700300 | (0x9) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 9216, 0x77700300 | (0xa) | (0x4 << 16) | (0x3 << 12) }, ++ { 10240, 0x77700300 | (0xa) | (0x4 << 16) | (0x4 << 12) }, ++ { 11264, 0x77700300 | (0xa) | (0x5 << 16) | (0x4 << 12) }, ++ { 12288, 0x77700300 | (0xa) | (0x5 << 16) | (0x5 << 12) }, ++ { 13312, 0x77700300 | (0xa) | (0x6 << 16) | (0x5 << 12) }, ++ { 14336, 0x77700300 | (0xa) | (0x6 << 16) | (0x6 << 12) }, ++ { 15360, 0x77700300 | (0xa) | (0x7 << 16) | (0x6 << 12) }, ++ { 16384, 0x77700300 | (0xa) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 18432, 0x77700300 | (0xb) | (0x4 << 16) | (0x3 << 12) }, ++ { 20480, 0x77700300 | (0xb) | (0x4 << 16) | (0x4 << 12) }, ++ { 22528, 0x77700300 | (0xb) | (0x5 << 16) | (0x4 << 12) }, ++ { 24576, 0x77700300 | (0xb) | (0x5 << 16) | (0x5 << 12) }, ++ { 26624, 0x77700300 | (0xb) | (0x6 << 16) | (0x5 << 12) }, ++ { 28672, 0x77700300 | (0xb) | (0x6 << 16) | (0x6 << 12) }, ++ { 30720, 0x77700300 | (0xb) | (0x7 << 16) | (0x6 << 12) }, ++ { 32768, 0x77700300 | (0xb) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 36864, 0x77700300 | (0xc) | (0x4 << 16) | (0x3 << 12) }, ++ { 40960, 0x77700300 | (0xc) | (0x4 << 16) | (0x4 << 12) }, ++ { 45056, 0x77700300 | (0xc) | (0x5 << 16) | (0x4 << 12) }, ++ { 49152, 0x77700300 | (0xc) | (0x5 << 16) | (0x5 << 12) }, ++ { 53248, 0x77700300 | (0xc) | (0x6 << 16) | (0x5 << 12) }, ++ { 57344, 0x77700300 | (0xc) | (0x6 << 16) | (0x6 << 12) }, ++ { 61440, 0x77700300 | (0xc) | (0x7 << 16) | (0x6 << 12) }, ++ { 65536, 0x77700300 | (0xc) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 73728, 0x77700300 | (0xd) | (0x4 << 16) | (0x3 << 12) }, ++ { 81920, 0x77700300 | (0xd) | (0x4 << 16) | (0x4 << 12) }, ++ { 90112, 0x77700300 | (0xd) | (0x5 << 16) | (0x4 << 12) }, ++ { 98304, 0x77700300 | (0xd) | (0x5 << 16) | (0x5 << 12) }, ++ { 106496, 0x77700300 | (0xd) | (0x6 << 16) | (0x5 << 12) }, ++ { 114688, 0x77700300 | (0xd) | (0x6 << 16) | (0x6 << 12) }, ++ { 122880, 0x77700300 | (0xd) | (0x7 << 16) | (0x6 << 12) }, ++ { 131072, 0x77700300 | (0xd) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 147456, 0x77700300 | (0xe) | (0x4 << 16) | (0x3 << 12) }, ++ { 163840, 0x77700300 | (0xe) | (0x4 << 16) | (0x4 << 12) }, ++ { 180224, 0x77700300 | (0xe) | (0x5 << 16) | (0x4 << 12) }, ++ { 196608, 0x77700300 | (0xe) | (0x5 << 16) | (0x5 << 12) }, ++ { 212992, 0x77700300 | (0xe) | (0x6 << 16) | (0x5 << 12) }, ++ { 229376, 0x77700300 | (0xe) | (0x6 << 16) | (0x6 << 12) }, ++ { 245760, 0x77700300 | (0xe) | (0x7 << 16) | (0x6 << 12) }, ++ { 262144, 0x77700300 | (0xe) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 294912, 0x77700300 | (0xf) | (0x4 << 16) | (0x3 << 12) }, ++ { 327680, 0x77700300 | (0xf) | (0x4 << 16) | (0x4 << 12) }, ++ { 360448, 0x77700300 | (0xf) | (0x5 << 16) | (0x4 << 12) }, ++ { 393216, 0x77700300 | (0xf) | (0x5 << 16) | (0x5 << 12) }, ++ { 425984, 0x77700300 | (0xf) | (0x6 << 16) | (0x5 << 12) }, ++ { 458752, 0x77700300 | (0xf) | (0x6 << 16) | (0x6 << 12) }, ++ { 491520, 0x77700300 | (0xf) | (0x7 << 16) | (0x6 << 12) }, ++ { 524288, 0x77700300 | (0xf) | (0x7 << 16) | (0x7 << 12) }, ++#endif ++}; ++ ++static inline void ast_i2c_write(struct ast_i2c_bus *i2c_bus, u32 val, u32 reg) ++{ ++#if 0 ++ printf("%x: W : reg %x , val: %x \n",i2c_bus->reg_base, reg, val); ++#endif ++ __raw_writel(val, i2c_bus->reg_base + reg); ++} ++ ++static inline u32 ast_i2c_read(struct ast_i2c_bus *i2c_bus, u32 reg) ++{ ++#if 0 ++ u32 val = __raw_readl(i2c_bus->reg_base + reg); ++ printf("%x: R : reg %x , val: %x \n",i2c_bus->reg_base, reg, val); ++ return val; ++#else ++ return __raw_readl(i2c_bus->reg_base + reg); ++#endif ++} ++ ++static u32 select_i2c_clock(unsigned int bus_clk) ++{ ++#if 0 ++ unsigned int clk, inc = 0, div, divider_ratio; ++ u32 SCL_Low, SCL_High, data; ++ ++ clk = ast_get_pclk(); ++// debug("pclk = %d \n",clk); ++ divider_ratio = clk / bus_clk; ++ for (div = 0; divider_ratio >= 16; div++) ++ { ++ inc |= (divider_ratio & 1); ++ divider_ratio >>= 1; ++ } ++ divider_ratio += inc; ++ SCL_Low = (divider_ratio >> 1) - 1; ++ SCL_High = divider_ratio - SCL_Low - 2; ++ data = 0x77700300 | (SCL_High << 16) | (SCL_Low << 12) | div; ++// printk("I2CD04 for %d = %08X\n", target_speed, data); ++ return data; ++#else ++ int i; ++ unsigned int clk; ++ u32 data; ++ ++ clk = ast_get_pclk(); ++ // debug("pclk = %d \n",clk); ++ ++ for (i = 0; ++ i < sizeof(i2c_timing_table) / sizeof(struct ast_i2c_timing_table); ++ i++) { ++ if ((clk / i2c_timing_table[i].divisor) < bus_clk) { ++ break; ++ } ++ } ++ data = i2c_timing_table[i].timing; ++ // printk("divisor [%d], timing [%x] \n", i2c_timing_table[i].divisor, ++ // i2c_timing_table[i].timing); ++ return data; ++#endif ++} ++ ++static int ast_i2c_wait_isr(struct ast_i2c_bus *i2c_bus, u32 flag) ++{ ++ int timeout = 0; ++ ++ while (!(ast_i2c_read(i2c_bus, I2C_INTR_STS_REG) & flag) && ++ (timeout < I2C_TIMEOUT_COUNT)) { ++ udelay(I2C_SLEEP_US); ++ timeout++; ++ } ++ ++ /* Clear Interrupt */ ++ ast_i2c_write(i2c_bus, 0xfffffff, I2C_INTR_STS_REG); ++ ++ if (timeout >= I2C_TIMEOUT_COUNT) { ++ debug("%s timed out:- flag: %x\n", __func__, flag); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static int ast_i2c_wait_tx(struct ast_i2c_bus *i2c_bus) ++{ ++ int sts; ++ int timeout = 0; ++ while (1) { ++ sts = ast_i2c_read(i2c_bus, I2C_INTR_STS_REG); ++ ++ if (timeout > I2C_TIMEOUT_COUNT) { ++ /* I2C Reset */ ++ debug("Timeout: Bus:%d, Addr:0x%02x\n", i2c_bus_num, ++ i2c_bus->addr); ++ ast_i2c_write(i2c_bus, 0, I2C_FUN_CTRL_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_MASTER_EN, ++ I2C_FUN_CTRL_REG); ++ ++ return -ETIMEDOUT; ++ } else if (sts & AST_I2CD_INTR_STS_TX_NAK) { ++ ast_i2c_write(i2c_bus, AST_I2CD_INTR_STS_TX_NAK, ++ I2C_INTR_STS_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_STOP_CMD, ++ I2C_CMD_REG); ++ ast_i2c_wait_isr(i2c_bus, ++ AST_I2CD_INTR_STS_NORMAL_STOP); ++ ++ return -EREMOTEIO; ++ } else if (sts & AST_I2CD_INTR_STS_TX_ACK) { ++ ast_i2c_write(i2c_bus, AST_I2CD_INTR_STS_TX_ACK, ++ I2C_INTR_STS_REG); ++ break; ++ } else { ++ timeout++; ++ } ++ udelay(I2C_SLEEP_US); ++ } ++ ++ return 0; ++} ++ ++static int ast_i2c_deblock(struct ast_i2c_bus *i2c_bus) ++{ ++ u32 csr; ++ int ret = 0; ++ ++ if ((csr = ast_i2c_read(i2c_bus, I2C_CMD_REG)) & ++ AST_I2CD_BUS_BUSY_STS) { ++ if ((csr & AST_I2CD_SDA_LINE_STS) && ++ (csr & AST_I2CD_SCL_LINE_STS)) { ++ /* Bus idle */ ++ debug("Bus(%d) idle\n", i2c_bus_num); ++ ret = 0; ++ } else if (csr & AST_I2CD_SDA_LINE_STS) { ++ /* send stop command */ ++ debug("Unterminated TXN in (%x), sending stop...\n", ++ csr); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_STOP_CMD, ++ I2C_CMD_REG); ++ ret = ast_i2c_wait_isr(i2c_bus, ++ AST_I2CD_INTR_STS_NORMAL_STOP); ++ } else if (csr & AST_I2CD_SCL_LINE_STS) { ++ /* Possibly stuck slave */ ++ debug("Bus stuck (%x), attempting recovery...\n", csr); ++ ast_i2c_write(i2c_bus, AST_I2CD_BUS_RECOVER_CMD_EN, ++ I2C_CMD_REG); ++ ret = ast_i2c_wait_isr(i2c_bus, ++ AST_I2CD_INTR_STS_BUS_RECOVER); ++ } else { ++ debug("Bus(%d) slave(0x%02x) busy. Reseting bus...\n", ++ i2c_bus_num, i2c_bus->addr); ++ ast_i2c_write(i2c_bus, 0, I2C_FUN_CTRL_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_MASTER_EN, ++ I2C_FUN_CTRL_REG); ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++static int ast_i2c_xfer(struct ast_i2c_bus *i2c_bus) ++{ ++ int sts, i, ret = 0; ++ ++ /* Clear Interrupt */ ++ ast_i2c_write(i2c_bus, 0xfffffff, I2C_INTR_STS_REG); ++ ++ /* Check for bus busy */ ++ ret = ast_i2c_deblock(i2c_bus); ++ if (ret != 0) ++ return ret; ++ ++ // first start ++ debug(" %sing %d byte%s %s 0x%02x\n", i2c_bus->flags ? "read" : "write", ++ i2c_bus->d_len, i2c_bus->d_len > 1 ? "s" : "", ++ i2c_bus->flags ? "from" : "to", i2c_bus->addr); ++ ++ if (i2c_bus->flags) { ++ // READ ++ if (i2c_bus->a_len) { ++ // send start ++ ast_i2c_write(i2c_bus, (i2c_bus->addr << 1), ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, ++ AST_I2CD_M_TX_CMD | AST_I2CD_M_START_CMD, ++ I2C_CMD_REG); ++ ++ /* Wait for ACK */ ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ ++ /* Send Offset */ ++ for (i = 0; i < i2c_bus->a_len; i++) { ++ debug("offset [%x] \n", i2c_bus->a_buf[i]); ++ ast_i2c_write(i2c_bus, i2c_bus->a_buf[i], ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD, ++ I2C_CMD_REG); ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ } ++ } ++ ++ // repeat-start ++ ast_i2c_write(i2c_bus, (i2c_bus->addr << 1) | 0x1, ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD | AST_I2CD_M_START_CMD, ++ I2C_CMD_REG); ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ ++ for (i = 0; i < i2c_bus->d_len; i++) { ++ if (i == (i2c_bus->d_len - 1)) { ++ ast_i2c_write(i2c_bus, ++ AST_I2CD_M_RX_CMD | ++ AST_I2CD_M_S_RX_CMD_LAST, ++ I2C_CMD_REG); ++ } else { ++ ast_i2c_write(i2c_bus, AST_I2CD_M_RX_CMD, ++ I2C_CMD_REG); ++ } ++ ++ ret = ast_i2c_wait_isr(i2c_bus, ++ AST_I2CD_INTR_STS_RX_DOWN); ++ if (ret != 0) ++ return ret; ++ ++ i2c_bus->d_buf[i] = ++ (ast_i2c_read(i2c_bus, I2C_BYTE_BUF_REG) & ++ AST_I2CD_RX_BYTE_BUFFER) >> ++ 8; ++ } ++ ast_i2c_write(i2c_bus, AST_I2CD_M_STOP_CMD, I2C_CMD_REG); ++ ret = ast_i2c_wait_isr(i2c_bus, AST_I2CD_INTR_STS_NORMAL_STOP); ++ if (ret != 0) ++ return ret; ++ ++ } else { ++ // Write ++ // send start ++ ast_i2c_write(i2c_bus, (i2c_bus->addr << 1), I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD | AST_I2CD_M_START_CMD, ++ I2C_CMD_REG); ++ ++ /* Wait for ACK */ ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ ++ /* Send Offset */ ++ for (i = 0; i < i2c_bus->a_len; i++) { ++ debug("offset [%x] \n", i2c_bus->a_buf[i]); ++ ast_i2c_write(i2c_bus, i2c_bus->a_buf[i], ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD, I2C_CMD_REG); ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ } ++ ++ /* Tx data */ ++ for (i = 0; i < i2c_bus->d_len; i++) { ++ debug("Tx data [%x] \n", i2c_bus->d_buf[i]); ++ ast_i2c_write(i2c_bus, i2c_bus->d_buf[i], ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD, I2C_CMD_REG); ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ } ++ ast_i2c_write(i2c_bus, AST_I2CD_M_STOP_CMD, I2C_CMD_REG); ++ ret = ast_i2c_wait_isr(i2c_bus, AST_I2CD_INTR_STS_NORMAL_STOP); ++ if (ret != 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/*****************************************************************************/ ++ ++unsigned int i2c_get_bus_speed(void) ++{ ++ return ast_i2c[i2c_bus_num].speed; ++} ++ ++int i2c_set_bus_speed(unsigned int speed) ++{ ++ struct ast_i2c_bus *i2c_bus = &ast_i2c[i2c_bus_num]; ++ ++ /* Set AC Timing */ ++ ast_i2c_write(i2c_bus, select_i2c_clock(speed), I2C_AC_TIMING_REG1); ++ ast_i2c_write(i2c_bus, AST_NO_TIMEOUT_CTRL, I2C_AC_TIMING_REG2); ++ ++ i2c_bus->speed = speed; ++ ++ return 0; ++} ++ ++unsigned int i2c_get_base(int bus_no) ++{ ++ switch (bus_no) { ++ case 0: ++ return AST_I2C_DEV0_BASE; ++ break; ++ case 1: ++ return AST_I2C_DEV1_BASE; ++ break; ++ case 2: ++ return AST_I2C_DEV2_BASE; ++ break; ++ case 3: ++ return AST_I2C_DEV3_BASE; ++ break; ++ case 4: ++ return AST_I2C_DEV4_BASE; ++ break; ++ case 5: ++ return AST_I2C_DEV5_BASE; ++ break; ++ case 6: ++ return AST_I2C_DEV6_BASE; ++ break; ++ case 7: ++ return AST_I2C_DEV7_BASE; ++ break; ++ case 8: ++ return AST_I2C_DEV8_BASE; ++ break; ++ case 9: ++ return AST_I2C_DEV9_BASE; ++ break; ++ case 10: ++ return AST_I2C_DEV10_BASE; ++ break; ++ case 11: ++ return AST_I2C_DEV11_BASE; ++ break; ++ case 12: ++ return AST_I2C_DEV12_BASE; ++ break; ++ case 13: ++ return AST_I2C_DEV13_BASE; ++ break; ++ default: ++ printf("i2c base error \n"); ++ break; ++ }; ++ return 0; ++} ++ ++void i2c_init(int speed, int slaveaddr) ++{ ++ int i = 0; ++ struct ast_i2c_bus *i2c_bus; ++ ++ // SCU I2C Reset ++ ast_scu_init_i2c(); ++ ++ /* This will override the speed selected in the fdt for that port */ ++ debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr); ++ ++ for (i = 0; i < CONFIG_SYS_MAX_I2C_BUS; i++) { ++ i2c_bus = &ast_i2c[i]; ++ i2c_bus->reg_base = i2c_get_base(i); ++ ++ i2c_bus->speed = CONFIG_SYS_I2C_SPEED; ++ i2c_bus->state = 0; ++ ++ // I2C Multi-Pin ++ ast_scu_multi_func_i2c(i); ++ ++ // I2CG Reset ++ ast_i2c_write(i2c_bus, 0, I2C_FUN_CTRL_REG); ++ ++ // Enable Master Mode ++ ast_i2c_write(i2c_bus, AST_I2CD_MASTER_EN, I2C_FUN_CTRL_REG); ++ ++ // SLAVE mode enable ++#if 0 ++ if(slaveaddr) { ++ ast_i2c_write(i2c_bus, slaveaddr, I2C_DEV_ADDR_REG); ++ ast_i2c_write(i2c_bus, ast_i2c_read(i2c_bus,I2C_FUN_CTRL_REG) | AST_I2CD_SLAVE_EN, I2C_FUN_CTRL_REG); ++ } ++#endif ++ ++ /* Set AC Timing */ ++ i2c_set_bus_speed(speed); ++ ++ // Clear Interrupt ++ ast_i2c_write(i2c_bus, 0xfffffff, I2C_INTR_STS_REG); ++ ++ /* Set interrupt generation of I2C controller */ ++ ast_i2c_write(i2c_bus, 0, I2C_INTR_CTRL_REG); ++ } ++ ++ i2c_bus_num = 0; ++ debug("end\n"); ++} ++ ++/* Probe to see if a chip is present. */ ++int i2c_probe(uchar addr) ++{ ++ uchar a_buf[1] = { 0 }; ++ ++ struct ast_i2c_bus *i2c_bus = &ast_i2c[i2c_bus_num]; ++ ++ debug("i2c_probe[bus:%d]: addr=0x%x\n", i2c_bus_num, addr); ++ ++ i2c_bus->addr = addr; ++ i2c_bus->flags = 1; ++ i2c_bus->a_len = 1; ++ i2c_bus->a_buf = (u8 *)&a_buf; ++ i2c_bus->d_len = 1; ++ i2c_bus->d_buf = (u8 *)&a_buf; ++ ++ return ast_i2c_xfer(i2c_bus); ++} ++ ++/* Read bytes */ ++int i2c_read(uchar addr, uint offset, int alen, uchar *buffer, int len) ++{ ++ uchar xoffset[4]; ++ struct ast_i2c_bus *i2c_bus = &ast_i2c[i2c_bus_num]; ++ ++ debug("i2c_read[bus:%d]: addr=0x%x, offset=0x%x, alen=0x%x len=0x%x\n", ++ i2c_bus_num, addr, offset, alen, len); ++ ++ if (alen > 4) { ++ debug("I2C read: addr len %d not supported\n", alen); ++ return 1; ++ } ++ ++ if (alen > 0) { ++ xoffset[0] = (offset >> 24) & 0xFF; ++ xoffset[1] = (offset >> 16) & 0xFF; ++ xoffset[2] = (offset >> 8) & 0xFF; ++ xoffset[3] = offset & 0xFF; ++ } ++ ++ i2c_bus->addr = addr; ++ i2c_bus->flags = 1; ++ i2c_bus->a_len = alen; ++ i2c_bus->a_buf = &xoffset[4 - alen]; ++ i2c_bus->d_len = len; ++ i2c_bus->d_buf = buffer; ++ ++ return ast_i2c_xfer(i2c_bus); ++} ++ ++/* Write bytes */ ++int i2c_write(uchar addr, uint offset, int alen, uchar *buffer, int len) ++{ ++ uchar xoffset[4]; ++ struct ast_i2c_bus *i2c_bus = &ast_i2c[i2c_bus_num]; ++ ++ debug("i2c_write[bus:%d]: addr=0x%x, offset=0x%x, alen=0x%x len=0x%x\n", ++ i2c_bus_num, addr, offset, alen, len); ++ ++ if (alen > 0) { ++ xoffset[0] = (offset >> 24) & 0xFF; ++ xoffset[1] = (offset >> 16) & 0xFF; ++ xoffset[2] = (offset >> 8) & 0xFF; ++ xoffset[3] = offset & 0xFF; ++ } ++ ++ i2c_bus->addr = addr; ++ i2c_bus->flags = 0; ++ i2c_bus->a_len = alen; ++ i2c_bus->a_buf = &xoffset[4 - alen]; ++ i2c_bus->d_len = len; ++ i2c_bus->d_buf = buffer; ++ ++ return ast_i2c_xfer(i2c_bus); ++} ++ ++#if defined(CONFIG_I2C_MULTI_BUS) ++/* ++ * Functions for multiple I2C bus handling ++ */ ++unsigned int i2c_get_bus_num(void) ++{ ++ return i2c_bus_num; ++} ++ ++int i2c_set_bus_num(unsigned int bus) ++{ ++ if (bus >= NUM_BUS) ++ return -1; ++ i2c_bus_num = bus; ++ ++ return 0; ++} ++#endif +diff --git a/drivers/i2c/ast_i2c.h b/drivers/i2c/ast_i2c.h +new file mode 100644 +index 0000000..7cff0e5 +--- /dev/null ++++ b/drivers/i2c/ast_i2c.h +@@ -0,0 +1,131 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2012-2020 ASPEED Technology Inc. ++ * Copyright 2016 IBM Corporation ++ * Copyright 2017 Google, Inc. ++ */ ++#ifndef __AST_I2C_H_ ++#define __AST_I2C_H_ ++ ++struct ast_i2c_regs { ++ u32 fcr; ++ u32 cactcr1; ++ u32 cactcr2; ++ u32 icr; ++ u32 isr; ++ u32 csr; ++ u32 sdar; ++ u32 pbcr; ++ u32 trbbr; ++#ifdef CONFIG_ASPEED_AST2500 ++ u32 dma_mbar; ++ u32 dma_tlr; ++#endif ++}; ++ ++/* Device Register Definition */ ++/* 0x00 : I2CD Function Control Register */ ++#define I2CD_BUFF_SEL_MASK (0x7 << 20) ++#define I2CD_BUFF_SEL(x) (x << 20) ++#define I2CD_M_SDA_LOCK_EN (0x1 << 16) ++#define I2CD_MULTI_MASTER_DIS (0x1 << 15) ++#define I2CD_M_SCL_DRIVE_EN (0x1 << 14) ++#define I2CD_MSB_STS (0x1 << 9) ++#define I2CD_SDA_DRIVE_1T_EN (0x1 << 8) ++#define I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7) ++#define I2CD_M_HIGH_SPEED_EN (0x1 << 6) ++#define I2CD_DEF_ADDR_EN (0x1 << 5) ++#define I2CD_DEF_ALERT_EN (0x1 << 4) ++#define I2CD_DEF_ARP_EN (0x1 << 3) ++#define I2CD_DEF_GCALL_EN (0x1 << 2) ++#define I2CD_SLAVE_EN (0x1 << 1) ++#define I2CD_MASTER_EN (0x1) ++ ++/* 0x04 : I2CD Clock and AC Timing Control Register #1 */ ++/* Base register value. These bits are always set by the driver. */ ++#define I2CD_CACTC_BASE 0xfff00300 ++#define I2CD_TCKHIGH_SHIFT 16 ++#define I2CD_TCKLOW_SHIFT 12 ++#define I2CD_THDDAT_SHIFT 10 ++#define I2CD_TO_DIV_SHIFT 8 ++#define I2CD_BASE_DIV_SHIFT 0 ++ ++/* 0x08 : I2CD Clock and AC Timing Control Register #2 */ ++#define I2CD_tTIMEOUT 1 ++#define I2CD_NO_TIMEOUT_CTRL 0 ++ ++/* 0x0c : I2CD Interrupt Control Register & ++ * 0x10 : I2CD Interrupt Status Register ++ * ++ * These share bit definitions, so use the same values for the enable & ++ * status bits. ++ */ ++#define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14) ++#define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13) ++#define I2CD_INTR_SMBUS_ALERT (0x1 << 12) ++#define I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11) ++#define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10) ++#define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9) ++#define I2CD_INTR_GCALL_ADDR (0x1 << 8) ++#define I2CD_INTR_SLAVE_MATCH (0x1 << 7) ++#define I2CD_INTR_SCL_TIMEOUT (0x1 << 6) ++#define I2CD_INTR_ABNORMAL (0x1 << 5) ++#define I2CD_INTR_NORMAL_STOP (0x1 << 4) ++#define I2CD_INTR_ARBIT_LOSS (0x1 << 3) ++#define I2CD_INTR_RX_DONE (0x1 << 2) ++#define I2CD_INTR_TX_NAK (0x1 << 1) ++#define I2CD_INTR_TX_ACK (0x1 << 0) ++ ++/* 0x14 : I2CD Command/Status Register */ ++#define I2CD_SDA_OE (0x1 << 28) ++#define I2CD_SDA_O (0x1 << 27) ++#define I2CD_SCL_OE (0x1 << 26) ++#define I2CD_SCL_O (0x1 << 25) ++#define I2CD_TX_TIMING (0x1 << 24) ++#define I2CD_TX_STATUS (0x1 << 23) ++ ++/* Tx State Machine */ ++#define I2CD_IDLE 0x0 ++#define I2CD_MACTIVE 0x8 ++#define I2CD_MSTART 0x9 ++#define I2CD_MSTARTR 0xa ++#define I2CD_MSTOP 0xb ++#define I2CD_MTXD 0xc ++#define I2CD_MRXACK 0xd ++#define I2CD_MRXD 0xe ++#define I2CD_MTXACK 0xf ++#define I2CD_SWAIT 0x1 ++#define I2CD_SRXD 0x4 ++#define I2CD_STXACK 0x5 ++#define I2CD_STXD 0x6 ++#define I2CD_SRXACK 0x7 ++#define I2CD_RECOVER 0x3 ++ ++#define I2CD_SCL_LINE_STS (0x1 << 18) ++#define I2CD_SDA_LINE_STS (0x1 << 17) ++#define I2CD_BUS_BUSY_STS (0x1 << 16) ++#define I2CD_SDA_OE_OUT_DIR (0x1 << 15) ++#define I2CD_SDA_O_OUT_DIR (0x1 << 14) ++#define I2CD_SCL_OE_OUT_DIR (0x1 << 13) ++#define I2CD_SCL_O_OUT_DIR (0x1 << 12) ++#define I2CD_BUS_RECOVER_CMD (0x1 << 11) ++#define I2CD_S_ALT_EN (0x1 << 10) ++#define I2CD_RX_DMA_ENABLE (0x1 << 9) ++#define I2CD_TX_DMA_ENABLE (0x1 << 8) ++ ++/* Command Bit */ ++#define I2CD_RX_BUFF_ENABLE (0x1 << 7) ++#define I2CD_TX_BUFF_ENABLE (0x1 << 6) ++#define I2CD_M_STOP_CMD (0x1 << 5) ++#define I2CD_M_S_RX_CMD_LAST (0x1 << 4) ++#define I2CD_M_RX_CMD (0x1 << 3) ++#define I2CD_S_TX_CMD (0x1 << 2) ++#define I2CD_M_TX_CMD (0x1 << 1) ++#define I2CD_M_START_CMD 0x1 ++ ++#define I2CD_RX_DATA_SHIFT 8 ++#define I2CD_RX_DATA_MASK (0xff << I2CD_RX_DATA_SHIFT) ++ ++#define I2C_HIGHSPEED_RATE 400000 ++ ++#endif /* __AST_I2C_H_ */ +diff --git a/include/configs/ast-common.h b/include/configs/ast-common.h +index b7d7192..0bc7f2d 100644 +--- a/include/configs/ast-common.h ++++ b/include/configs/ast-common.h +@@ -84,6 +84,11 @@ + #define CONFIG_SYS_MAXARGS 16 + #define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE + ++/* I2C config */ ++#define CONFIG_I2C_MULTI_BUS 1 ++#define CONFIG_SYS_MAX_I2C_BUS 8 ++#define CONFIG_SYS_I2C_SPEED 100000 ++ + /* + * Optional MTD and UBI support + */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0027-CPLD-u-boot-commands-support-for-PFR.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0027-CPLD-u-boot-commands-support-for-PFR.patch new file mode 100644 index 000000000..d8e7c4645 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0027-CPLD-u-boot-commands-support-for-PFR.patch @@ -0,0 +1,300 @@ +From 35a50c959b290ba8a6f0e70a42ae952b65df8a9d Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 7 May 2019 11:26:35 +0530 +Subject: [PATCH] CPLD u-boot commands support for PFR + +Implemented the cpld command in u-boot for +communicating with PFR CPLD. + +Tested: +Simulated test on different I2C bus and slave +as we don't have hardware available yet. +ast# cpld dump +*** Dumping CPLD Registers *** +0x0000 | 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f +---------------------------------------------------------- +0x0000 | 03 00 00 00 01 09 00 f5 01 09 19 cb 46 4c 45 -- +0x0001 | -- 52 4f 4e 49 43 53 cf 53 2d 31 31 30 30 41 44 +0x0002 | 55 -- 30 2d 32 30 31 ca 47 38 34 30 32 -- 2d -- +0x0003 | 30 37 c2 30 31 cc 45 58 57 44 36 34 39 30 30 38 +............................. +ast# cpld read 0x00 +CPLD read successful. Reg:0x00 Val:0x03 +ast# cpld write 0x00 0x04 +CPLD write successful. Reg:0x00 Val:0x04 +ast# cpld read 0x00 +CPLD read successful. Reg:0x00 Val:0x04 +ast# + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + cmd/Makefile | 1 + + cmd/cpld.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 245 insertions(+) + create mode 100644 cmd/cpld.c + +diff --git a/cmd/Makefile b/cmd/Makefile +index a1731be..c8ac0af 100644 +--- a/cmd/Makefile ++++ b/cmd/Makefile +@@ -66,6 +66,7 @@ obj-$(CONFIG_CMD_FUSE) += fuse.o + obj-$(CONFIG_CMD_GETTIME) += gettime.o + obj-$(CONFIG_CMD_GPIO) += gpio.o + obj-$(CONFIG_CMD_I2C) += i2c.o ++obj-$(CONFIG_CMD_I2C) += cpld.o + obj-$(CONFIG_CMD_IOTRACE) += iotrace.o + obj-$(CONFIG_CMD_HASH) += hash.o + obj-$(CONFIG_CMD_IDE) += ide.o +diff --git a/cmd/cpld.c b/cmd/cpld.c +new file mode 100644 +index 0000000..63220cb +--- /dev/null ++++ b/cmd/cpld.c +@@ -0,0 +1,244 @@ ++/* ++ * Copyright (c) 2018-2019 Intel Corporation ++ * Written by AppaRao Puli <apparao.puli@intel.com> ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include <common.h> ++#include <command.h> ++#include <cli.h> ++#include <i2c.h> ++#include <errno.h> ++#include <linux/compiler.h> ++ ++#define PFR_CPLD_I2C_BUSNO 5 ++#define PFR_CPLD_SLAVE_ADDR 0x0E ++ ++#define CPLD_READ_TIMEOUT_ATTEMPTS 5 ++ ++/* Some CPLD registers are self cleared after read. ++ * We should skip them reading to avoid functionality impact.*/ ++/* TODO: Need to get this list from CPLD team. */ ++static uchar cpld_reg_skip_read[] = {}; ++ ++static bool skip_cpld_reg_read(u32 reg) ++{ ++ int size = ARRAY_SIZE(cpld_reg_skip_read); ++ for (int i = 0; i < size; i++) { ++ if (reg == cpld_reg_skip_read[i]) ++ return true; ++ } ++ ++ return false; ++} ++ ++static int do_cpld_write(cmd_tbl_t *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ int ret = 0; ++ int current_bus_no; ++ u32 reg_addr; ++ uchar value; ++ int chip = (PFR_CPLD_SLAVE_ADDR >> 1); ++ ++ if (argc != 3) ++ return CMD_RET_USAGE; ++ ++ reg_addr = simple_strtoul(argv[1], NULL, 16); ++ if (reg_addr > 0xFF) { ++ printf("Invalid register. Valid range[0x00-0xFF]."); ++ return CMD_RET_FAILURE; ++ } ++ value = simple_strtoul(argv[2], NULL, 16); ++ ++ /* Get current I2C bus number to restore later. */ ++ current_bus_no = i2c_get_bus_num(); ++ ++ /* Set I2C bus number to PFR CPLD I2C bus. */ ++ ret = i2c_set_bus_num(PFR_CPLD_I2C_BUSNO); ++ if (ret) { ++ printf("Failure changing bus number (%d)\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ ret = i2c_write(chip, reg_addr, 1, &value, 1); ++ if (ret) { ++ printf("Error writing the chip: %d\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ printf("CPLD write successful. Reg:0x%02x Val:0x%02x\n", reg_addr, ++ value); ++ ++done: ++ /* Restore I2C bus number */ ++ if (i2c_set_bus_num(current_bus_no)) ++ printf("Error in restoring bus number.\n"); ++ ++ return ret; ++} ++ ++static int do_cpld_read(cmd_tbl_t *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ int ret = 0; ++ int current_bus_no; ++ u32 reg_addr; ++ uchar value[1]; ++ int chip = (PFR_CPLD_SLAVE_ADDR >> 1); ++ ++ if (argc != 2) ++ return CMD_RET_USAGE; ++ ++ reg_addr = simple_strtoul(argv[1], NULL, 16); ++ if (reg_addr > 0xFF) { ++ printf("Invalid register. Valid range[0x00-0xFF]."); ++ return CMD_RET_FAILURE; ++ } ++ ++ /* Get current I2C bus number to restore later. */ ++ current_bus_no = i2c_get_bus_num(); ++ ++ /* Set I2C bus number to PFR CPLD I2C bus. */ ++ ret = i2c_set_bus_num(PFR_CPLD_I2C_BUSNO); ++ if (ret) { ++ printf("Failure changing bus number (%d)\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ if (skip_cpld_reg_read(reg_addr)) { ++ printf("CPLD register(0x%02x) reading is not allowed.\n", ++ reg_addr); ++ ret = 0; ++ goto done; ++ } ++ ++ ret = i2c_read(chip, reg_addr, 1, value, 1); ++ if (ret) { ++ printf("Error reading the chip: %d\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ printf("CPLD read successful. Reg:0x%02x Val:0x%02x\n", reg_addr, ++ value[0]); ++ ++done: ++ /* Restore I2C bus number */ ++ if (i2c_set_bus_num(current_bus_no)) ++ printf("Error in restoring bus number.\n"); ++ ++ return ret; ++} ++ ++static int do_cpld_dump(cmd_tbl_t *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ int ret = 0; ++ int current_bus_no; ++ u32 reg_addr = 0x00; ++ uchar value[1]; ++ int chip = (PFR_CPLD_SLAVE_ADDR >> 1); ++ ++ if (argc != 1) ++ return CMD_RET_USAGE; ++ ++ /* Get current I2C bus number to restore later. */ ++ current_bus_no = i2c_get_bus_num(); ++ ++ /* Set I2C bus number to PFR CPLD I2C bus. */ ++ ret = i2c_set_bus_num(PFR_CPLD_I2C_BUSNO); ++ if (ret) { ++ printf("Failure changing bus number (%d)\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ printf("*** Dumping CPLD Registers ***\n", reg_addr, value); ++ printf("0x%04x | ", reg_addr); ++ for (int i = 0; i < 0x10; i++) ++ printf(" %02x", i); ++ printf("\n----------------------------------------------------------\n"); ++ ++ while (reg_addr <= 0xFF) { ++ if ((reg_addr % 16) == 0) ++ printf("0x%04x | ", (reg_addr / 16)); ++ ++ if (skip_cpld_reg_read(reg_addr)) { ++ printf(" --"); ++ } else { ++ int timeout = 0; ++ while (i2c_read(chip, reg_addr, 1, value, 1) != 0) { ++ if (timeout++ >= CPLD_READ_TIMEOUT_ATTEMPTS) { ++ printf("\nERROR: Reading the chip: %d\n", ++ ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ /* Need delay for I2C devices continous read */ ++ mdelay(3 * timeout); ++ } ++ printf(" %02x", value[0]); ++ } ++ ++ reg_addr++; ++ if ((reg_addr % 16) == 0) ++ printf("\n"); ++ } ++ ++done: ++ /* Restore I2C bus number */ ++ if (i2c_set_bus_num(current_bus_no)) ++ printf("Error in restoring bus number.\n"); ++ ++ return ret; ++} ++static cmd_tbl_t cmd_cpld_sub[] = { ++ U_BOOT_CMD_MKENT(dump, 1, 1, do_cpld_dump, "", ""), ++ U_BOOT_CMD_MKENT(read, 2, 1, do_cpld_read, "", ""), ++ U_BOOT_CMD_MKENT(write, 3, 1, do_cpld_write, "", "") ++}; ++ ++/** ++ * do_cpld() - Handle the "cpld" command-line command ++ * @cmdtp: Command data struct pointer ++ * @flag: Command flag ++ * @argc: Command-line argument count ++ * @argv: Array of command-line arguments ++ * ++ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative ++ * on error. ++ */ ++static int do_cpld(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ cmd_tbl_t *c = NULL; ++ ++ if (argc < 2) ++ return CMD_RET_USAGE; ++ ++ /* Strip off leading 'cpld' command argument */ ++ argc--; ++ argv++; ++ ++ if (argc) ++ c = find_cmd_tbl(argv[0], cmd_cpld_sub, ++ ARRAY_SIZE(cmd_cpld_sub)); ++ ++ if (c) ++ return c->cmd(cmdtp, flag, argc, argv); ++ else ++ return CMD_RET_USAGE; ++} ++ ++#ifdef CONFIG_SYS_LONGHELP ++static char cpld_help_text[] = ++ "cpld dump - Dump all CPLD registers.\n" ++ "cpld read <reg> - Read CPLD register.\n" ++ "cpld write <reg> <val> - Write CPLD register.\n"; ++#endif ++ ++U_BOOT_CMD(cpld, 4, 1, do_cpld, "PFR CPLD information", cpld_help_text); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch new file mode 100644 index 000000000..7601f6dea --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch @@ -0,0 +1,61 @@ +From 56d13790a713659e34eca884ce36dca76b3bdf3d Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 13 May 2019 23:49:02 +0530 +Subject: [PATCH] Enabling uart1&uart2 in u-boot for BIOS messages + +Added uart init function in u-boot aspeed code +to enable uart1 and uart2 for BIOS serial messages. + +Tested: +Forced BMC to stop in u-boot( using Force Firmware Update +Jumper), AC cycled system for multiple times, booted system +to uefi, checked bios serial logs working fine and accessed +keyboard in uefi without any issues. + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + board/aspeed/ast-g5/ast-g5-intel.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 86b422f..fe5128f 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -414,6 +414,26 @@ void ast_g5_intel_late_init(void) + free(cmdline_new); + } + ++static void uart_init(void) ++{ ++ u32 val; ++ ++ /* Enable UART1 and UART2 for BIOS messages */ ++ val = ast_scu_read(AST_SCU_FUN_PIN_CTRL2); ++ ++ /* UART1 */ ++ val |= (SCU_FUN_PIN_UART1_NCTS | SCU_FUN_PIN_UART1_NDCD | ++ SCU_FUN_PIN_UART1_NDSR | SCU_FUN_PIN_UART1_NRI | ++ SCU_FUN_PIN_UART1_NDTR | SCU_FUN_PIN_UART1_NRTS | ++ SCU_FUN_PIN_UART1_TXD | SCU_FUN_PIN_UART1_RXD); ++ /* UART2 */ ++ val |= (SCU_FUN_PIN_UART2_NCTS | SCU_FUN_PIN_UART2_NDCD | ++ SCU_FUN_PIN_UART2_NDSR | SCU_FUN_PIN_UART2_NRI | ++ SCU_FUN_PIN_UART2_NDTR | SCU_FUN_PIN_UART2_NRTS | ++ SCU_FUN_PIN_UART2_TXD | SCU_FUN_PIN_UART2_RXD); ++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL2); ++} ++ + static void pwm_init(void) + { + uint32_t val; +@@ -482,6 +502,7 @@ extern void espi_init(void); + extern void kcs_init(void); + void ast_g5_intel(void) + { ++ uart_init(); + pwm_init(); + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend new file mode 100644 index 000000000..6026f8d91 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend @@ -0,0 +1,37 @@ +FILESEXTRAPATHS_append_wolfpass:= "${THISDIR}/files:" + +# the meta-phosphor layer adds this patch, which conflicts +# with the intel layout for environment +SRC_URI_remove_wolfpass = " file://0001-configs-ast-Add-redundnant-env.patch" + +SRC_URI_append_wolfpass = " \ + file://0001-flash-use-readX-writeX-not-udelay.patch \ + file://0002-intel-layout-environment-addr.patch \ + file://0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch \ + file://0005-enable-passthrough-in-uboot.patch \ + file://0006-Add-Aspeed-g5-interrupt-support.patch \ + file://0007-Add-espi-support.patch \ + file://0008-add-sgio-support-for-port80-snoop-post-LEDs.patch \ + file://0009-Add-basic-GPIO-support.patch \ + file://0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch \ + file://0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch \ + file://0012-Add-status-and-ID-LED-support.patch \ + file://0013-aspeed-Add-Pwm-Driver.patch \ + file://0014-Keep-interrupts-enabled-until-last-second.patch \ + file://0015-Rewrite-memmove-to-optimize-on-word-transfers.patch \ + file://0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch \ + file://0017-Enable-Macronix-and-Micron-SPI-support.patch \ + file://0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch \ + file://0019-u-boot-full-platform-reset-espi-oob-ready.patch \ + file://0020-Enable-PCIe-L1-support.patch \ + file://0020-Add-system-reset-status-support.patch \ + file://0021-Config-host-uart-clock-source-using-environment-vari.patch \ + file://0022-KCS-driver-support-in-uBoot.patch \ + file://0023-Add-TPM-enable-pulse-triggering.patch \ + file://0024-IPMI-command-handler-implementation-in-uboot.patch \ + file://0025-Manufacturing-mode-physical-presence-detection.patch \ + file://0026-Aspeed-I2C-support-in-U-Boot.patch \ + file://0027-CPLD-u-boot-commands-support-for-PFR.patch \ + file://0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch \ + " +SRC_URI_append_wolfpass += "${@bb.utils.contains('IMAGE_TYPE', 'pfr', 'file://0022-u-boot-env-change-for-PFR-image.patch', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed_%.bbappend new file mode 100644 index 000000000..6026f8d91 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed_%.bbappend @@ -0,0 +1,37 @@ +FILESEXTRAPATHS_append_wolfpass:= "${THISDIR}/files:" + +# the meta-phosphor layer adds this patch, which conflicts +# with the intel layout for environment +SRC_URI_remove_wolfpass = " file://0001-configs-ast-Add-redundnant-env.patch" + +SRC_URI_append_wolfpass = " \ + file://0001-flash-use-readX-writeX-not-udelay.patch \ + file://0002-intel-layout-environment-addr.patch \ + file://0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch \ + file://0005-enable-passthrough-in-uboot.patch \ + file://0006-Add-Aspeed-g5-interrupt-support.patch \ + file://0007-Add-espi-support.patch \ + file://0008-add-sgio-support-for-port80-snoop-post-LEDs.patch \ + file://0009-Add-basic-GPIO-support.patch \ + file://0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch \ + file://0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch \ + file://0012-Add-status-and-ID-LED-support.patch \ + file://0013-aspeed-Add-Pwm-Driver.patch \ + file://0014-Keep-interrupts-enabled-until-last-second.patch \ + file://0015-Rewrite-memmove-to-optimize-on-word-transfers.patch \ + file://0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch \ + file://0017-Enable-Macronix-and-Micron-SPI-support.patch \ + file://0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch \ + file://0019-u-boot-full-platform-reset-espi-oob-ready.patch \ + file://0020-Enable-PCIe-L1-support.patch \ + file://0020-Add-system-reset-status-support.patch \ + file://0021-Config-host-uart-clock-source-using-environment-vari.patch \ + file://0022-KCS-driver-support-in-uBoot.patch \ + file://0023-Add-TPM-enable-pulse-triggering.patch \ + file://0024-IPMI-command-handler-implementation-in-uboot.patch \ + file://0025-Manufacturing-mode-physical-presence-detection.patch \ + file://0026-Aspeed-I2C-support-in-U-Boot.patch \ + file://0027-CPLD-u-boot-commands-support-for-PFR.patch \ + file://0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch \ + " +SRC_URI_append_wolfpass += "${@bb.utils.contains('IMAGE_TYPE', 'pfr', 'file://0022-u-boot-env-change-for-PFR-image.patch', '', d)}" |