diff options
Diffstat (limited to 'SamsungPlatformPkg/ExynosPkg/Exynos5250')
101 files changed, 28046 insertions, 0 deletions
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.c new file mode 100644 index 000000000..d1b5a3be6 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.c @@ -0,0 +1,692 @@ +/** @file + Template for Timer Architecture Protocol driver of the ARM flavor + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Protocol/GraphicsOutput.h> +#include <Protocol/DevicePath.h> +#include <Protocol/ExynosGpio.h> +#include <Platform/ArmPlatform.h> +#include <Platform/Exynos5250.h> +#include "DisplayDxe.h" + + +typedef struct { + VENDOR_DEVICE_PATH DisplayDevicePath; + EFI_DEVICE_PATH EndDevicePath; +} DISPLAY_DEVICE_PATH; + +DISPLAY_DEVICE_PATH gDisplayDevicePath = +{ + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8)(sizeof(VENDOR_DEVICE_PATH)), + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8), + EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } +}; + +#define LCD_WIDTH 1280 +#define LCD_HEIGHT 800 + +#define VCLK 62946240 + +#define SRC_CLK 800000000 + +/** + This function configures the MIPI-DSIM channel +**/ +INT32 s5p_mipi_dsi_wr_data(UINT32 data_id, UINT32 data0, UINT32 data1) +{ + UINT32 DSIM1BaseAddr = PcdGet32(PcdDSIM1Base); + UINT32 data_cnt = 0; + UINT32 payload = 0; + UINT32 timeout_count = 100000; + + MicroSecondDelay(20000); + + /* in case that data count is more then 4 */ + for (data_cnt=0; data_cnt<data1; data_cnt+=4) { + /* + * after sending 4bytes per one time, + * send remainder data less then 4. + */ + if ((data1 - data_cnt) < 4) { + if ((data1 - data_cnt) == 3) { + payload = *(UINT8 *)(data0 + data_cnt) | (*(UINT8 *)(data0 + (data_cnt + 1))) << 8 | (*(UINT8 *)(data0 + (data_cnt + 2))) << 16; + } else if ((data1 - data_cnt) == 2) { + payload = *(UINT8 *)(data0 + data_cnt) | (*(UINT8 *)(data0 + (data_cnt + 1))) << 8; + } else if ((data1 - data_cnt) == 1) { + payload = *(UINT8 *)(data0 + data_cnt); + } + + MmioWrite32(DSIM1BaseAddr + DSIM_PAYLOAD, payload); + /* send 4bytes per one time. */ + } else { + payload = *(UINT8 *)(data0 + data_cnt) | (*(UINT8 *)(data0 + (data_cnt + 1))) << 8 | \ + (*(UINT8 *)(data0 + (data_cnt + 2))) << 16 | (*(UINT8 *)(data0 + (data_cnt + 3))) << 24; + + MmioWrite32(DSIM1BaseAddr + DSIM_PAYLOAD, payload); + } + } + + MmioWrite32(DSIM1BaseAddr + DSIM_PKTHDR, ((((data1 & 0xFF00) >> 8)<<16) | ((data1 & 0xFF)<<8) | ((data_id & 0x3F)<<0))); + + while(1) { + if(timeout_count == 0) + return -1; + + if(MmioRead32(DSIM1BaseAddr + DSIM_INTSRC) & (0x1<<29)) { + MmioWrite32(DSIM1BaseAddr + DSIM_INTSRC, (0x1<<29)); + return 1; + } + else if((MmioRead32(DSIM1BaseAddr + DSIM_FIFOCTRL) & 0xF00000) == 0) + return -1; + timeout_count--; + } +} + +INT32 lcd_display_on(VOID) +{ + UINT8 initcode_013c[6] = {0x3c, 0x01, 0x03, 0x00, 0x02, 0x00}; + UINT8 initcode_0114[6] = {0x14, 0x01, 0x02, 0x00, 0x00, 0x00}; + UINT8 initcode_0164[6] = {0x64, 0x01, 0x05, 0x00, 0x00, 0x00}; + UINT8 initcode_0168[6] = {0x68, 0x01, 0x05, 0x00, 0x00, 0x00}; + UINT8 initcode_016c[6] = {0x6c, 0x01, 0x05, 0x00, 0x00, 0x00}; + UINT8 initcode_0170[6] = {0x70, 0x01, 0x05, 0x00, 0x00, 0x00}; + UINT8 initcode_0134[6] = {0x34, 0x01, 0x1f, 0x00, 0x00, 0x00}; + UINT8 initcode_0210[6] = {0x10, 0x02, 0x1f, 0x00, 0x00, 0x00}; + UINT8 initcode_0104[6] = {0x04, 0x01, 0x01, 0x00, 0x00, 0x00}; + UINT8 initcode_0204[6] = {0x04, 0x02, 0x01, 0x00, 0x00, 0x00}; + UINT8 initcode_0450[6] = {0x50, 0x04, 0x20, 0x01, 0xfa, 0x00}; + UINT8 initcode_0454[6] = {0x54, 0x04, 0x20, 0x00, 0x50, 0x00}; + UINT8 initcode_0458[6] = {0x58, 0x04, 0x00, 0x05, 0x30, 0x00}; + UINT8 initcode_045c[6] = {0x5c, 0x04, 0x05, 0x00, 0x0a, 0x00}; + UINT8 initcode_0460[6] = {0x60, 0x04, 0x20, 0x03, 0x0a, 0x00}; + UINT8 initcode_0464[6] = {0x64, 0x04, 0x01, 0x00, 0x00, 0x00}; + UINT8 initcode_04a0_1[6] = {0xa0, 0x04, 0x06, 0x80, 0x44, 0x00}; + UINT8 initcode_04a0_2[6] = {0xa0, 0x04, 0x06, 0x80, 0x04, 0x00}; + UINT8 initcode_0504[6] = {0x04, 0x05, 0x04, 0x00, 0x00, 0x00}; + UINT8 initcode_049c[6] = {0x9c, 0x04, 0x0d, 0x00, 0x00, 0x00}; + + /* Initialize MIPI LCD */ + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_013c, sizeof(initcode_013c)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0114, sizeof(initcode_0114)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0164, sizeof(initcode_0164)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0168, sizeof(initcode_0168)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_016c, sizeof(initcode_016c)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0170, sizeof(initcode_0170)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0134, sizeof(initcode_0134)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0210, sizeof(initcode_0210)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0104, sizeof(initcode_0104)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0204, sizeof(initcode_0204)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0450, sizeof(initcode_0450)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0454, sizeof(initcode_0454)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0458, sizeof(initcode_0458)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_045c, sizeof(initcode_045c)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0460, sizeof(initcode_0460)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0464, sizeof(initcode_0464)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_04a0_1, sizeof(initcode_04a0_1)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_04a0_2, sizeof(initcode_04a0_2)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_0504, sizeof(initcode_0504)) == -1) + return 0; + MicroSecondDelay(6000); + if(s5p_mipi_dsi_wr_data(0x29, (UINT32)initcode_049c, sizeof(initcode_049c)) == -1) + return 0; + MicroSecondDelay(800000); + + return 1; +} + +VOID ConfigureMIPI(VOID) +{ + UINT32 DSIM1BaseAddr = PcdGet32(PcdDSIM1Base); + UINT32 DSIM_status; + BOOLEAN config_done = FALSE; + + /* Enable MIPI-DSIM clock */ + MmioAndThenOr32((PcdGet32(PcdCmuBase) + CLK_GATE_IP_DISP1_OFFSET), ~CLK_GATE_DSIM1_MASK,CLK_GATE_DSIM1_MASK); + + while(!config_done) { + /* Enable MIPI PHY1 */ + MmioAndThenOr32((PcdGet32(PcdPmuBase) +PMU_MIPI_PHY1_CONTROL_OFFSET), ~(1<<0), (1<<0)); + /* Reset DSIM part of MIPI PHY1 */ + MmioAndThenOr32((PcdGet32(PcdPmuBase) +PMU_MIPI_PHY1_CONTROL_OFFSET), ~(1<<2), (1<<2)); + + /* DSIM SW Reset */ + MmioOr32(DSIM1BaseAddr + DSIM_SWRST, (1<<0)); + + /* Disable swap of Dp/Dn channel of data and clock lanes */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_PHYACCHR1, ~(0x3<<0), ((0 & 0x3)<<0)); + + /* DSIM SW Reset */ + MmioOr32(DSIM1BaseAddr + DSIM_SWRST, (1<<0)); + + /* Initialize FIFO pointer */ + MmioAnd32(DSIM1BaseAddr + DSIM_FIFOCTRL, ~(0x1F<<0)); + MicroSecondDelay(10000); + MmioOr32(DSIM1BaseAddr + DSIM_FIFOCTRL, (0x1F<<0)); + + /* DSI configuration */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_CONFIG, ~((0x1<<28) | (0x1F<<20) | (0x3<<5)), (0x3<<5)); + MmioOr32(DSIM1BaseAddr + DSIM_CONFIG, ((0x1<<0)|(0x1<<1)|(0x1<<2)|(0x1<<3)|(0x1<<4))); + + /* clock configuration */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_CLKCTRL, ~(0x3<<25), (0x0<<25)); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_PHYACCHR, ~(0x7<<5), ((0x1<<14)|(0x3<<5))); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_PLLCTRL, ~(0x7FFFF<<1), ((3<<13)|(115<<4)|(1<<1))); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_PLLCTRL, ~(0xF<<28), (0x0<<28)); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_PLLCTRL, ~(0x7<<20), (0x0<<20)); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_PLLCTRL, ~(0xF<<24), (0x8<<24)); + MmioWrite32(DSIM1BaseAddr + DSIM_PLLTMR, 500); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_CLKCTRL, ~(0x1<<27), (0x0<<27)); + + /* Enable PLL */ + MmioWrite32(DSIM1BaseAddr + DSIM_INTSRC, (0x1<<31)); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_PLLCTRL, ~(0x1<<23), (0x1<<23)); + while(1) { + if(MmioRead32(DSIM1BaseAddr + DSIM_STATUS) & (0x1<<31)) + break; + } + + /* Enable byte clock */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_CLKCTRL, ~(0x1<<24), (0x1<<24)); + /* Enable escape clock */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_CLKCTRL, ~((0x1<<28) | (0xFFFF<<0)), ((0x1<<28) | (144<<0))); + /* Enable escape clock data and clock lanes */ + MmioOr32(DSIM1BaseAddr + DSIM_CLKCTRL, (0x1F<<19)); + + MicroSecondDelay(100000); + + while(1) { + DSIM_status = MmioRead32(DSIM1BaseAddr + DSIM_STATUS); + if((DSIM_status & (0xF<<0)) && ((DSIM_status & (0x1<<8)) || (DSIM_status & (0x1<<10)))) + break; + } + + /* BTA sequence counters */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_ESCMODE, ~(0x7FF<<21), ((0xF &0x7FF) << 21)); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_TIMEOUT, ~(0xFF<<16), (0xFF<<16)); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_TIMEOUT, ~(0xFFFF<<0), (0xFFFF<<0)); + + /* Enable HS clock */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_CLKCTRL, ~(0x1<<31), (0x1<<31)); + + /* Set CPU transfer mode */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_ESCMODE, ~(0x1<<7), (0x1<<7)); + + /* Set display mode */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_MVPORCH, ~((0xF<<28)|(0x7FF<<16)|(0x7FF<<0)), ((0xF<<28)|(0x4<<16)|(0x4<<0))); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_MHPORCH, ~((0xFFFF<<16)|(0xFFFF<<0)), ((0x4<<16)|(0x4<<0))); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_MSYNC, ~((0x3FF<<22)|(0xFFFF<<0)), ((0x4<<22)|(0x4<<0))); + + MmioAnd32(DSIM1BaseAddr + DSIM_MDRESOL, ~(0x1<<31)); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_MDRESOL, ~((0x7FF<<16)|(0x7FF<<0)), ((0x1<<31)|(LCD_HEIGHT<<16)|(LCD_WIDTH<<0))); + MmioAndThenOr32(DSIM1BaseAddr + DSIM_CONFIG, ~((0x3<<26)|(0x1<<25)|(0x3<<18)|(0x7<<12)|(0x3<<16)|(0x7<<8)), \ + ((0x1<<26)|(0x1<<25)|(0x7<<12))); + + /* Clear interrupt status */ + MmioWrite32(DSIM1BaseAddr + DSIM_INTSRC, (0x1<<29)); + + if(lcd_display_on() == 1) + config_done = TRUE; + + /* Reset CPU transfer mode */ + MmioAndThenOr32(DSIM1BaseAddr + DSIM_ESCMODE, ~(0x1<<7), (0x0<<7)); + + if(!config_done) + MmioOr32(DSIM1BaseAddr + DSIM_SWRST, (1<<0)); /* DSIM SW Reset */ + } +} + +VOID s5p_mipi_dsi_func_reset(VOID) +{ + UINT32 DSIM1BaseAddr = PcdGet32(PcdDSIM1Base); + + MmioOr32(DSIM1BaseAddr + DSIM_SWRST, (1<<16)); +} + +/** + This function configures the Power Domain of the LCD 0 Module to Normal Mode. +**/ +VOID ConfigurePower(VOID) +{ + UINT32 PrevGateState; + + /* Enable FIMD1 power domain */ + PrevGateState = MmioRead32((PcdGet32(PcdCmuBase) + CLK_GATE_IP_DISP1_OFFSET)); + MmioWrite32((PcdGet32(PcdCmuBase) + CLK_GATE_IP_DISP1_OFFSET), 0xFFFFFFFF); + + MmioWrite32((PcdGet32(PcdPmuBase) + PMU_DISP1_CONFIGURATION_OFFSET), LOCAL_PWR_ENABLE); + while( (MmioRead32((PcdGet32(PcdPmuBase) + PMU_DISP1_STATUS_OFFSET)) & LOCAL_PWR_ENABLE) != \ + LOCAL_PWR_ENABLE); + + MmioWrite32((PcdGet32(PcdCmuBase) + CLK_GATE_IP_DISP1_OFFSET), PrevGateState); +} + +/** + This function configures Clock Source,Clock gating,Clock Divider and Mask values for the + FIMD0 in the LCD0 Module + +**/ +VOID ConfigureClk(VOID) +{ + MmioAndThenOr32((PcdGet32(PcdCmuBase) + CLK_GATE_IP_DISP1_OFFSET), \ + ~CLK_GATE_FIMD1_MASK,CLK_GATE_FIMD1_MASK); + + /* MPLL is the clock source of FIMD1 IP */ + MmioAndThenOr32((PcdGet32(PcdCmuBase) + CLK_SRC_DISP1_0_OFFSET), \ + ~CLK_SRC_FIMD1_MASK, CLK_SRC_FIMD1_SEL(FIMD1_SCLKMPLL)); + + /* Considering MPLL=800000000(800 MHz), SCLK_FIMD0=800000000(800 MHz) => DIV => (800/800) => 1 + The DIV value to be programmed should be (1 -1) = 0 */ + MmioAndThenOr32((PcdGet32(PcdCmuBase) + CLK_DIV_DISP1_0_OFFSET), \ + ~CLK_DIV_FIMD1_MASK, CLK_DIV_FIMD1_SEL(FIMD1_CLK_DIV)); + + MmioOr32((PcdGet32(PcdCmuBase) + CLK_SRC_MASK_DISP1_0_OFFSET), CLK_SRC_DISP1_0_UNMASK); +} + +VOID lcd_power_on(VOID) +{ + EFI_STATUS Status; + EXYNOS_GPIO *Gpio; + + Status = gBS->LocateProtocol(&gSamsungPlatformGpioProtocolGuid, NULL, (VOID **)&Gpio); + ASSERT_EFI_ERROR(Status); + + /* reset */ + Gpio->Set(Gpio,LCD_RESET,GPIO_MODE_OUTPUT_1); + MicroSecondDelay(20000); + Gpio->Set(Gpio,LCD_RESET,GPIO_MODE_OUTPUT_0); + MicroSecondDelay(20000); + Gpio->Set(Gpio,LCD_RESET,GPIO_MODE_OUTPUT_1); + MicroSecondDelay(20000); + + /* power */ + Gpio->Set(Gpio,LCD_POWER,GPIO_MODE_OUTPUT_0); + MicroSecondDelay(20000); + Gpio->Set(Gpio,LCD_POWER,GPIO_MODE_OUTPUT_1); + MicroSecondDelay(20000); + + /*backlight */ + Gpio->Set(Gpio,LCD_BACKLIGHT,GPIO_MODE_OUTPUT_0); + MicroSecondDelay(20000); + Gpio->Set(Gpio,LCD_BACKLIGHT,GPIO_MODE_OUTPUT_1); + MicroSecondDelay(20000); +} + + +VOID LCD_Initialize(VOID) +{ + UINTN div; + UINT32 Fimd1BaseAddr = PcdGet32(PcdFIMD1Base); + UINT32 FBAddr = PcdGet32(PcdFrameBufferBase); + + gBS->SetMem((VOID *)FBAddr, (LCD_WIDTH*LCD_HEIGHT*4), 0x0); + + ConfigurePower(); + + /* Power up the LCD */ + lcd_power_on(); + + /* Initialize MIPI-DSIM */ + ConfigureMIPI(); + + ConfigureClk(); + + /* Set FIMD1 bypass */ + MmioOr32((PcdGet32(PcdSysBase) + SYS_DISP1BLK_CFG_OFFSET), FIMDBYPASS_DISP1); + + /* Configure FIMD */ + MmioAndThenOr32(Fimd1BaseAddr + VIDCON1_OFFSET, ~S5P_VIDCON1_FIXVCLK_MASK, (S5P_VIDCON1_IVCLK_RISING_EDGE | \ + S5P_VIDCON1_FIXVCLK_RUN)); + + MmioOr32(Fimd1BaseAddr + SHADOWCON_OFFSET, S5P_SHADOWCON_PROTECT(0)); + + div = SRC_CLK / VCLK; + + MmioAndThenOr32(Fimd1BaseAddr + VIDCON0_OFFSET, ~S5P_VIDCON0_CLKVAL_F_MASK, (S5P_VIDCON0_CLKDIR_DIVIDED | \ + S5P_VIDCON0_CLKVAL_F(div - 1) | S5P_VIDCON0_ENVID_ENABLE | S5P_VIDCON0_ENVID_F_ENABLE)); + MmioOr32(Fimd1BaseAddr + VIDTCON0_OFFSET, (S5P_VIDTCON0_VBPD(3) | S5P_VIDTCON0_VFPD(3) | S5P_VIDTCON0_VSPW(3))); + MmioOr32(Fimd1BaseAddr + VIDTCON1_OFFSET, (S5P_VIDTCON1_HBPD(3) | S5P_VIDTCON1_HFPD(3) | S5P_VIDTCON1_HSPW(3))); + + MmioOr32(Fimd1BaseAddr + VIDTCON2_OFFSET, (S5P_VIDTCON2_HOZVAL(LCD_WIDTH - 1) | S5P_VIDTCON2_LINEVAL(LCD_HEIGHT - 1))); + + MmioWrite32(Fimd1BaseAddr + VIDADDR_START0_OFFSET(0), FBAddr); + MmioWrite32(Fimd1BaseAddr + VIDADDR_END0_OFFSET(0), (FBAddr + (LCD_WIDTH * LCD_HEIGHT * 4))); + MmioWrite32(Fimd1BaseAddr + VIDADDR_SIZE_OFFSET(0), (S5P_VIDADDR_PAGEWIDTH(LCD_WIDTH * 4) | S5P_VIDADDR_OFFSIZE(0))); + + MmioWrite32(Fimd1BaseAddr + VIDOSD_A_OFFSET(0), (S5P_VIDOSD_LEFT_X(0) | S5P_VIDOSD_TOP_Y(0))); + MmioWrite32(Fimd1BaseAddr + VIDOSD_B_OFFSET(0), (S5P_VIDOSD_RIGHT_X(LCD_WIDTH - 1) | S5P_VIDOSD_BOTTOM_Y(LCD_HEIGHT - 1))); + MmioWrite32(Fimd1BaseAddr + VIDOSD_C_OFFSET(0), S5P_VIDOSD_SIZE(LCD_WIDTH * LCD_HEIGHT)); + + MmioOr32(Fimd1BaseAddr + SHADOWCON_OFFSET, S5P_SHADOWCON_CH_ENABLE(0)); + + MmioAndThenOr32(Fimd1BaseAddr + WINCON_OFFSET(0), ~(S5P_WINCON_BURSTLEN_MASK | S5P_WINCON_BPPMODE_MASK), \ + (S5P_WINCON_WSWP_ENABLE | S5P_WINCON_BURSTLEN_16WORD | S5P_WINCON_BPPMODE_24BPP_888 | S5P_WINCON_ENWIN_ENABLE)); + + MmioAnd32(Fimd1BaseAddr + SHADOWCON_OFFSET, ~(S5P_SHADOWCON_PROTECT(0))); + +#if defined(LCD_MIPI_TC358764) + s5p_mipi_dsi_func_reset(); +#endif +} + +EFI_STATUS +EFIAPI +DisplayQueryMode( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ); + +EFI_STATUS +EFIAPI +DisplaySetMode( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber + ); + +EFI_STATUS +EFIAPI +DisplayBlt( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ); + +EFI_GRAPHICS_OUTPUT_PROTOCOL gDisplay = { + DisplayQueryMode, + DisplaySetMode, + DisplayBlt, + NULL +}; + + +EFI_STATUS +EFIAPI +DisplayQueryMode( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +{ + EFI_STATUS Status; + + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), + (VOID **)Info + ); + ASSERT_EFI_ERROR(Status); + + *SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + (*Info)->Version = This->Mode->Info->Version; + (*Info)->HorizontalResolution = This->Mode->Info->HorizontalResolution; + (*Info)->VerticalResolution = This->Mode->Info->VerticalResolution; + (*Info)->PixelFormat = This->Mode->Info->PixelFormat; + (*Info)->PixelsPerScanLine = This->Mode->Info->PixelsPerScanLine; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DisplaySetMode( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DisplayBlt( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ) +{ + UINT8 *VidBuf, *BltBuf, *VidBuf1; + UINTN i, j; + + switch(BltOperation) { + case EfiBltVideoFill: + BltBuf = (UINT8 *)BltBuffer; + + for(i=0;i<Height;i++) { + VidBuf = (UINT8 *)((UINT32)This->Mode->FrameBufferBase + \ + (DestinationY + i)*This->Mode->Info->PixelsPerScanLine*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + \ + DestinationX*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + for(j=0;j<Width;j++) { + gBS->CopyMem((VOID *)VidBuf, (VOID *)BltBuf, sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + VidBuf += sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } + } + break; + + case EfiBltVideoToBltBuffer: + if(Delta == 0) + Delta = Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + + for(i=0;i<Height;i++) { + VidBuf = (UINT8 *)((UINT32)This->Mode->FrameBufferBase + \ + (SourceY + i)*This->Mode->Info->PixelsPerScanLine*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + \ + SourceX*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + BltBuf = (UINT8 *)((UINT32)BltBuffer + (DestinationY + i)*Delta + DestinationX*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + for(j=0;j<Width;j++) { + gBS->CopyMem((VOID *)BltBuf, (VOID *)VidBuf, sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + VidBuf += sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + BltBuf += sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } + } + break; + + case EfiBltBufferToVideo: + if(Delta == 0) + Delta = Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + + for(i=0;i<Height;i++) { + VidBuf = (UINT8 *)((UINT32)This->Mode->FrameBufferBase + \ + (DestinationY + i)*This->Mode->Info->PixelsPerScanLine*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + \ + DestinationX*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + BltBuf = (UINT8 *)((UINT32)BltBuffer + (SourceY + i)*Delta + SourceX*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + for(j=0;j<Width;j++) { + gBS->CopyMem((VOID *)VidBuf, (VOID *)BltBuf, sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + VidBuf += sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + BltBuf += sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } + } + break; + + case EfiBltVideoToVideo: + for(i=0;i<Height;i++) { + VidBuf = (UINT8 *)((UINT32)This->Mode->FrameBufferBase + \ + (SourceY + i)*This->Mode->Info->PixelsPerScanLine*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + \ + SourceX*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + VidBuf1 = (UINT8 *)((UINT32)This->Mode->FrameBufferBase + \ + (DestinationY + i)*This->Mode->Info->PixelsPerScanLine*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + \ + DestinationX*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + for(j=0;j<Width;j++) { + gBS->CopyMem((VOID *)VidBuf1, (VOID *)VidBuf, sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + VidBuf += sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + VidBuf1 += sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } + } + break; + + default: + ASSERT_EFI_ERROR(EFI_SUCCESS); + } + + return EFI_SUCCESS; +} + + + +/** + Initialize the state information for the Display Dxe + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +DisplayDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + EFI_GUID DevicePathProtocolGuid = EFI_DEVICE_PATH_PROTOCOL_GUID; + UINT32 FBAddr = PcdGet32(PcdFrameBufferBase); + + /* Initialize Display */ + LCD_Initialize(); + if(gDisplay.Mode == NULL){ + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), + (VOID **)&gDisplay.Mode + ); + ASSERT_EFI_ERROR(Status); + ZeroMem(gDisplay.Mode,sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)); + } + if(gDisplay.Mode->Info==NULL){ + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), + (VOID **)&gDisplay.Mode->Info + ); + ASSERT_EFI_ERROR(Status); + ZeroMem(gDisplay.Mode->Info,sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); + } + /* Fill out mode information */ + gDisplay.Mode->MaxMode = 1; + gDisplay.Mode->Mode = 0; + gDisplay.Mode->Info->Version = 0; + gDisplay.Mode->Info->HorizontalResolution = LCD_WIDTH; + gDisplay.Mode->Info->VerticalResolution = LCD_HEIGHT; + gDisplay.Mode->Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; + gDisplay.Mode->Info->PixelsPerScanLine = LCD_WIDTH; + gDisplay.Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + gDisplay.Mode->FrameBufferBase = FBAddr; + gDisplay.Mode->FrameBufferSize = (LCD_WIDTH * LCD_HEIGHT * 4); + +#if 0 + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &DevicePathProtocolGuid, + &gDisplayDevicePath, + &GraphicsOutputProtocolGuid, + &gDisplay, + NULL); +#else + { + EFI_HANDLE gUEFIDisplayHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &gUEFIDisplayHandle, + &DevicePathProtocolGuid, + &gDisplayDevicePath, + &GraphicsOutputProtocolGuid, + &gDisplay, + NULL); + + } +#endif + + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.h new file mode 100644 index 000000000..5b784f384 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.h @@ -0,0 +1,277 @@ +/** @file +* +* Copyright (c) 2012, Samsung Electronics Co. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + + +#ifndef _DisplayDxe_H__ +#define _DisplayDxe_H__ + +/* + * Bit Definitions +*/ + +/* VIDCON0 */ +#define S5P_VIDCON0_DSI_DISABLE (0 << 30) +#define S5P_VIDCON0_DSI_ENABLE (1 << 30) +#define S5P_VIDCON0_SCAN_PROGRESSIVE (0 << 29) +#define S5P_VIDCON0_SCAN_INTERLACE (1 << 29) +#define S5P_VIDCON0_SCAN_MASK (1 << 29) +#define S5P_VIDCON0_VIDOUT_RGB (0 << 26) +#define S5P_VIDCON0_VIDOUT_ITU (1 << 26) +#define S5P_VIDCON0_VIDOUT_I80LDI0 (2 << 26) +#define S5P_VIDCON0_VIDOUT_I80LDI1 (3 << 26) +#define S5P_VIDCON0_VIDOUT_WB_RGB (4 << 26) +#define S5P_VIDCON0_VIDOUT_WB_I80LDI0 (6 << 26) +#define S5P_VIDCON0_VIDOUT_WB_I80LDI1 (7 << 26) +#define S5P_VIDCON0_VIDOUT_MASK (7 << 26) +#define S5P_VIDCON0_PNRMODE_RGB_P (0 << 17) +#define S5P_VIDCON0_PNRMODE_BGR_P (1 << 17) +#define S5P_VIDCON0_PNRMODE_RGB_S (2 << 17) +#define S5P_VIDCON0_PNRMODE_BGR_S (3 << 17) +#define S5P_VIDCON0_PNRMODE_MASK (3 << 17) +#define S5P_VIDCON0_PNRMODE_SHIFT (17) +#define S5P_VIDCON0_CLKVALUP_ALWAYS (0 << 16) +#define S5P_VIDCON0_CLKVALUP_START_FRAME (1 << 16) +#define S5P_VIDCON0_CLKVALUP_MASK (1 << 16) +#define S5P_VIDCON0_CLKVAL_F(x) (((x) & 0xff) << 6) +#define S5P_VIDCON0_CLKVAL_F_MASK (0xff << 6) +#define S5P_VIDCON0_VCLKEN_NORMAL (0 << 5) +#define S5P_VIDCON0_VCLKEN_FREERUN (1 << 5) +#define S5P_VIDCON0_VCLKEN_MASK (1 << 5) +#define S5P_VIDCON0_CLKDIR_DIRECTED (0 << 4) +#define S5P_VIDCON0_CLKDIR_DIVIDED (1 << 4) +#define S5P_VIDCON0_CLKDIR_MASK (1 << 4) +#define S5P_VIDCON0_CLKSEL_HCLK (0 << 2) +#define S5P_VIDCON0_CLKSEL_SCLK (1 << 2) +#define S5P_VIDCON0_CLKSEL_MASK (1 << 2) +#define S5P_VIDCON0_ENVID_ENABLE (1 << 1) +#define S5P_VIDCON0_ENVID_DISABLE (0 << 1) +#define S5P_VIDCON0_ENVID_F_ENABLE (1 << 0) +#define S5P_VIDCON0_ENVID_F_DISABLE (0 << 0) + +/* VIDCON1 */ +#define S5P_VIDCON1_FIXVCLK_MASK (3 << 9) +#define S5P_VIDCON1_FIXVCLK_HOLD (0 << 9) +#define S5P_VIDCON1_FIXVCLK_RUN (1 << 9) +#define S5P_VIDCON1_IVCLK_FALLING_EDGE (0 << 7) +#define S5P_VIDCON1_IVCLK_RISING_EDGE (1 << 7) +#define S5P_VIDCON1_IHSYNC_NORMAL (0 << 6) +#define S5P_VIDCON1_IHSYNC_INVERT (1 << 6) +#define S5P_VIDCON1_IVSYNC_NORMAL (0 << 5) +#define S5P_VIDCON1_IVSYNC_INVERT (1 << 5) +#define S5P_VIDCON1_IVDEN_NORMAL (0 << 4) +#define S5P_VIDCON1_IVDEN_INVERT (1 << 4) + +/* VIDCON2 */ +#define S5P_VIDCON2_EN601_DISABLE (0 << 23) +#define S5P_VIDCON2_EN601_ENABLE (1 << 23) +#define S5P_VIDCON2_EN601_MASK (1 << 23) +#define S5P_VIDCON2_WB_DISABLE (0 << 15) +#define S5P_VIDCON2_WB_ENABLE (1 << 15) +#define S5P_VIDCON2_WB_MASK (1 << 15) +#define S5P_VIDCON2_TVFORMATSEL_HW (0 << 14) +#define S5P_VIDCON2_TVFORMATSEL_SW (1 << 14) +#define S5P_VIDCON2_TVFORMATSEL_MASK (1 << 14) +#define S5P_VIDCON2_TVFORMATSEL_YUV422 (1 << 12) +#define S5P_VIDCON2_TVFORMATSEL_YUV444 (2 << 12) +#define S5P_VIDCON2_TVFORMATSEL_YUV_MASK (3 << 12) +#define S5P_VIDCON2_ORGYUV_YCBCR (0 << 8) +#define S5P_VIDCON2_ORGYUV_CBCRY (1 << 8) +#define S5P_VIDCON2_ORGYUV_MASK (1 << 8) +#define S5P_VIDCON2_YUVORD_CBCR (0 << 7) +#define S5P_VIDCON2_YUVORD_CRCB (1 << 7) +#define S5P_VIDCON2_YUVORD_MASK (1 << 7) + +/* PRTCON */ +#define S5P_PRTCON_UPDATABLE (0 << 11) +#define S5P_PRTCON_PROTECT (1 << 11) + +/* VIDTCON0 */ +#define S5P_VIDTCON0_VBPDE(x) (((x) & 0xff) << 24) +#define S5P_VIDTCON0_VBPD(x) (((x) & 0xff) << 16) +#define S5P_VIDTCON0_VFPD(x) (((x) & 0xff) << 8) +#define S5P_VIDTCON0_VSPW(x) (((x) & 0xff) << 0) + +/* VIDTCON1 */ +#define S5P_VIDTCON1_VFPDE(x) (((x) & 0xff) << 24) +#define S5P_VIDTCON1_HBPD(x) (((x) & 0xff) << 16) +#define S5P_VIDTCON1_HFPD(x) (((x) & 0xff) << 8) +#define S5P_VIDTCON1_HSPW(x) (((x) & 0xff) << 0) + +/* VIDTCON2 */ +#define S5P_VIDTCON2_LINEVAL(x) (((x) & 0x7ff) << 11) +#define S5P_VIDTCON2_HOZVAL(x) (((x) & 0x7ff) << 0) + +/* Window 0~4 Control - WINCONx */ +#define S5P_WINCON_DATAPATH_DMA (0 << 22) +#define S5P_WINCON_DATAPATH_LOCAL (1 << 22) +#define S5P_WINCON_DATAPATH_MASK (1 << 22) +#define S5P_WINCON_BUFSEL_0 (0 << 20) +#define S5P_WINCON_BUFSEL_1 (1 << 20) +#define S5P_WINCON_BUFSEL_MASK (1 << 20) +#define S5P_WINCON_BUFSEL_SHIFT (20) +#define S5P_WINCON_BUFAUTO_DISABLE (0 << 19) +#define S5P_WINCON_BUFAUTO_ENABLE (1 << 19) +#define S5P_WINCON_BUFAUTO_MASK (1 << 19) +#define S5P_WINCON_BITSWP_DISABLE (0 << 18) +#define S5P_WINCON_BITSWP_ENABLE (1 << 18) +#define S5P_WINCON_BITSWP_SHIFT (18) +#define S5P_WINCON_BYTESWP_DISABLE (0 << 17) +#define S5P_WINCON_BYTESWP_ENABLE (1 << 17) +#define S5P_WINCON_BYTESWP_SHIFT (17) +#define S5P_WINCON_HAWSWP_DISABLE (0 << 16) +#define S5P_WINCON_HAWSWP_ENABLE (1 << 16) +#define S5P_WINCON_HAWSWP_SHIFT (16) +#define S5P_WINCON_WSWP_DISABLE (0 << 15) +#define S5P_WINCON_WSWP_ENABLE (1 << 15) +#define S5P_WINCON_WSWP_SHIFT (15) +#define S5P_WINCON_INRGB_RGB (0 << 13) +#define S5P_WINCON_INRGB_YUV (1 << 13) +#define S5P_WINCON_INRGB_MASK (1 << 13) +#define S5P_WINCON_BURSTLEN_16WORD (0 << 9) +#define S5P_WINCON_BURSTLEN_8WORD (1 << 9) +#define S5P_WINCON_BURSTLEN_4WORD (2 << 9) +#define S5P_WINCON_BURSTLEN_MASK (3 << 9) +#define S5P_WINCON_ALPHA_MULTI_DISABLE (0 << 7) +#define S5P_WINCON_ALPHA_MULTI_ENABLE (1 << 7) +#define S5P_WINCON_BLD_PLANE (0 << 6) +#define S5P_WINCON_BLD_PIXEL (1 << 6) +#define S5P_WINCON_BLD_MASK (1 << 6) +#define S5P_WINCON_BPPMODE_1BPP (0 << 2) +#define S5P_WINCON_BPPMODE_2BPP (1 << 2) +#define S5P_WINCON_BPPMODE_4BPP (2 << 2) +#define S5P_WINCON_BPPMODE_8BPP_PAL (3 << 2) +#define S5P_WINCON_BPPMODE_8BPP (4 << 2) +#define S5P_WINCON_BPPMODE_16BPP_565 (5 << 2) +#define S5P_WINCON_BPPMODE_16BPP_A555 (6 << 2) +#define S5P_WINCON_BPPMODE_18BPP_666 (8 << 2) +#define S5P_WINCON_BPPMODE_18BPP_A665 (9 << 2) +#define S5P_WINCON_BPPMODE_24BPP_888 (0xb << 2) +#define S5P_WINCON_BPPMODE_24BPP_A887 (0xc << 2) +#define S5P_WINCON_BPPMODE_32BPP (0xd << 2) +#define S5P_WINCON_BPPMODE_16BPP_A444 (0xe << 2) +#define S5P_WINCON_BPPMODE_15BPP_555 (0xf << 2) +#define S5P_WINCON_BPPMODE_MASK (0xf << 2) +#define S5P_WINCON_BPPMODE_SHIFT (2) +#define S5P_WINCON_ALPHA0_SEL (0 << 1) +#define S5P_WINCON_ALPHA1_SEL (1 << 1) +#define S5P_WINCON_ALPHA_SEL_MASK (1 << 1) +#define S5P_WINCON_ENWIN_DISABLE (0 << 0) +#define S5P_WINCON_ENWIN_ENABLE (1 << 0) + +/* WINCON1 special */ +#define S5P_WINCON1_VP_DISABLE (0 << 24) +#define S5P_WINCON1_VP_ENABLE (1 << 24) +#define S5P_WINCON1_LOCALSEL_FIMC1 (0 << 23) +#define S5P_WINCON1_LOCALSEL_VP (1 << 23) +#define S5P_WINCON1_LOCALSEL_MASK (1 << 23) + +/* WINSHMAP */ +#define S5P_SHADOWCON_PROTECT(x) (1 << (10 + x)) +#define S5P_SHADOWCON_CH_ENABLE(x) (1 << (x)) +#define S5P_SHADOWCON_CH_DISABLE(x) (1 << (x)) + + +/* VIDOSDxA, VIDOSDxB */ +#define S5P_VIDOSD_LEFT_X(x) (((x) & 0x7ff) << 11) +#define S5P_VIDOSD_TOP_Y(x) (((x) & 0x7ff) << 0) +#define S5P_VIDOSD_RIGHT_X(x) (((x) & 0x7ff) << 11) +#define S5P_VIDOSD_BOTTOM_Y(x) (((x) & 0x7ff) << 0) + +/* VIDOSD0C, VIDOSDxD */ +#define S5P_VIDOSD_SIZE(x) (((x) & 0xffffff) << 0) + +/* VIDOSDxC (1~4) */ +#define S5P_VIDOSD_ALPHA0_R(x) (((x) & 0xf) << 20) +#define S5P_VIDOSD_ALPHA0_G(x) (((x) & 0xf) << 16) +#define S5P_VIDOSD_ALPHA0_B(x) (((x) & 0xf) << 12) +#define S5P_VIDOSD_ALPHA1_R(x) (((x) & 0xf) << 8) +#define S5P_VIDOSD_ALPHA1_G(x) (((x) & 0xf) << 4) +#define S5P_VIDOSD_ALPHA1_B(x) (((x) & 0xf) << 0) +#define S5P_VIDOSD_ALPHA0_SHIFT (12) +#define S5P_VIDOSD_ALPHA1_SHIFT (0) + +/* Start Address */ +#define S5P_VIDADDR_START_VBANK(x) (((x) & 0xff) << 24) +#define S5P_VIDADDR_START_VBASEU(x) (((x) & 0xffffff) << 0) + +/* End Address */ +#define S5P_VIDADDR_END_VBASEL(x) (((x) & 0xffffff) << 0) + +/* Buffer Size */ +#define S5P_VIDADDR_OFFSIZE(x) (((x) & 0x1fff) << 13) +#define S5P_VIDADDR_PAGEWIDTH(x) (((x) & 0x1fff) << 0) + +/* WIN Color Map */ +#define S5P_WINMAP_COLOR(x) ((x) & 0xffffff) + +/* VIDINTCON0 */ +#define S5P_VIDINTCON0_SYSMAINCON_DISABLE (0 << 19) +#define S5P_VIDINTCON0_SYSMAINCON_ENABLE (1 << 19) +#define S5P_VIDINTCON0_SYSSUBCON_DISABLE (0 << 18) +#define S5P_VIDINTCON0_SYSSUBCON_ENABLE (1 << 18) +#define S5P_VIDINTCON0_SYSIFDONE_DISABLE (0 << 17) +#define S5P_VIDINTCON0_SYSIFDONE_ENABLE (1 << 17) +#define S5P_VIDINTCON0_FRAMESEL0_BACK (0 << 15) +#define S5P_VIDINTCON0_FRAMESEL0_VSYNC (1 << 15) +#define S5P_VIDINTCON0_FRAMESEL0_ACTIVE (2 << 15) +#define S5P_VIDINTCON0_FRAMESEL0_FRONT (3 << 15) +#define S5P_VIDINTCON0_FRAMESEL0_MASK (3 << 15) +#define S5P_VIDINTCON0_FRAMESEL1_NONE (0 << 13) +#define S5P_VIDINTCON0_FRAMESEL1_BACK (1 << 13) +#define S5P_VIDINTCON0_FRAMESEL1_VSYNC (2 << 13) +#define S5P_VIDINTCON0_FRAMESEL1_FRONT (3 << 13) +#define S5P_VIDINTCON0_INTFRMEN_DISABLE (0 << 12) +#define S5P_VIDINTCON0_INTFRMEN_ENABLE (1 << 12) +#define S5P_VIDINTCON0_FIFOSEL_WIN4 (1 << 11) +#define S5P_VIDINTCON0_FIFOSEL_WIN3 (1 << 10) +#define S5P_VIDINTCON0_FIFOSEL_WIN2 (1 << 9) +#define S5P_VIDINTCON0_FIFOSEL_WIN1 (1 << 6) +#define S5P_VIDINTCON0_FIFOSEL_WIN0 (1 << 5) +#define S5P_VIDINTCON0_FIFOSEL_ALL (0x73 << 5) +#define S5P_VIDINTCON0_FIFOSEL_MASK (0x73 << 5) +#define S5P_VIDINTCON0_FIFOLEVEL_25 (0 << 2) +#define S5P_VIDINTCON0_FIFOLEVEL_50 (1 << 2) +#define S5P_VIDINTCON0_FIFOLEVEL_75 (2 << 2) +#define S5P_VIDINTCON0_FIFOLEVEL_EMPTY (3 << 2) +#define S5P_VIDINTCON0_FIFOLEVEL_FULL (4 << 2) +#define S5P_VIDINTCON0_FIFOLEVEL_MASK (7 << 2) +#define S5P_VIDINTCON0_INTFIFO_DISABLE (0 << 1) +#define S5P_VIDINTCON0_INTFIFO_ENABLE (1 << 1) +#define S5P_VIDINTCON0_INT_DISABLE (0 << 0) +#define S5P_VIDINTCON0_INT_ENABLE (1 << 0) +#define S5P_VIDINTCON0_INT_MASK (1 << 0) + +/* VIDINTCON1 */ +#define S5P_VIDINTCON1_INTVPPEND (1 << 5) +#define S5P_VIDINTCON1_INTI80PEND (1 << 2) +#define S5P_VIDINTCON1_INTFRMPEND (1 << 1) +#define S5P_VIDINTCON1_INTFIFOPEND (1 << 0) + +/* WINMAP */ +#define S5P_WINMAP_ENABLE (1 << 24) + +/* WxKEYCON0 (1~4) */ +#define S5P_KEYCON0_KEYBLEN_DISABLE (0 << 26) +#define S5P_KEYCON0_KEYBLEN_ENABLE (1 << 26) +#define S5P_KEYCON0_KEY_DISABLE (0 << 25) +#define S5P_KEYCON0_KEY_ENABLE (1 << 25) +#define S5P_KEYCON0_DIRCON_MATCH_FG (0 << 24) +#define S5P_KEYCON0_DIRCON_MATCH_BG (1 << 24) +#define S5P_KEYCON0_COMPKEY(x) (((x) & 0xffffff) << 0) + +/* WxKEYCON1 (1~4) */ +#define S5P_KEYCON1_COLVAL(x) (((x) & 0xffffff) << 0) + + +#endif // _Display_Dxe_H__ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.inf new file mode 100644 index 000000000..3667e00a2 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/DisplayDxe/DisplayDxe.inf @@ -0,0 +1,65 @@ +## @file +# +# Component description file for GraphicsConsole module +# +# This is the main routine for initializing the Graphics Console support routines. +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DisplayDxe + FILE_GUID = c5deae31-fad2-4030-841b-cfc9644d2c5b + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DisplayDxeInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = gGraphicsConsoleDriverBinding +# COMPONENT_NAME = gGraphicsConsoleComponentName +# COMPONENT_NAME2 = gGraphicsConsoleComponentName2 +# + +[Sources] + DisplayDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + SamsungPlatformPkg/SamsungPlatformPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + MemoryAllocationLib + UefiDriverEntryPoint + IoLib + TimerLib + +[Protocols] + gEfiGraphicsOutputProtocolGuid ## TO_START + gSamsungPlatformGpioProtocolGuid ## GPIO Protocol + +[Guids] + +[Pcd] + gExynosPkgTokenSpaceGuid.PcdCmuBase + gExynosPkgTokenSpaceGuid.PcdPmuBase + gExynosPkgTokenSpaceGuid.PcdSysBase + gExynosPkgTokenSpaceGuid.PcdFIMD1Base + gExynosPkgTokenSpaceGuid.PcdFrameBufferBase + gExynosPkgTokenSpaceGuid.PcdDSIM1Base diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c new file mode 100644 index 000000000..51a8c1617 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c @@ -0,0 +1,788 @@ +/** @file + Template for Timer Architecture Protocol driver of the ARM flavor + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Library/NetLib.h> +#include <Library/TimerLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Protocol/SimpleNetwork.h> +#include <Protocol/DevicePath.h> +#include <Protocol/ExynosGpio.h> +#include <Platform/ArmPlatform.h> +#include "EthDxe.h" + + +ETH_DXE_PRIVATE_DATA gEthDxePrivateTemplate = { + ETH_DXE_PRIVATE_DATA_SIGNATURE, + { + EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, + EthStart, + EthStop, + EthInitialize, + EthReset, + EthShutdown, + EthReceiveFilters, + EthStationAddress, + EthStatistics, + EthMCastIpToMac, + EthNvData, + EthGetStatus, + EthTransmit, + EthReceive, + NULL, + NULL + }, + { + EfiSimpleNetworkStopped, // State + NET_ETHER_ADDR_LEN, // HwAddressSize + NET_ETHER_HEADER_SIZE, // MediaHeaderSize + 1500, // MaxPacketSize + 0, // NvRamSize + 0, // NvRamAccessSize + 0, // ReceiveFilterMask + 0, // ReceiveFilterSetting + MAX_MCAST_FILTER_CNT, // MaxMCastFilterCount + 0, // MCastFilterCount + { + 0 + }, // MCastFilter + { + 0 + }, // CurrentAddress + { + 0 + }, // BroadcastAddress + { + 0 + }, // PermanentAddress + NET_IFTYPE_ETHERNET, // IfType + FALSE, // MacAddressChangeable + FALSE, // MultipleTxSupported + FALSE, // MediaPresentSupported + TRUE // MediaPresent + }, + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8)(sizeof(VENDOR_DEVICE_PATH)), + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8), + EFI_SIMPLE_NETWORK_PROTOCOL_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } +}; + + +UINT32 smc911x_reg_read(UINT32 offset) +{ + UINT32 regBase = PcdGet32(PcdSMC911XBase); + UINT32 val; + + val = (MmioRead16(regBase + offset) & 0xFFFF) | ((MmioRead16(regBase + offset + 2) & 0xFFFF) << 16); + + return val; +} + +VOID smc911x_reg_write(UINT32 offset, UINT32 val) +{ + UINT32 regBase = PcdGet32(PcdSMC911XBase); + + MmioWrite16(regBase + offset, ((UINT16)(val & 0xFFFF))); + MmioWrite16(regBase + offset + 2, ((UINT16)((val & 0xFFFF0000)>>16))); +} + +UINT32 smc911x_get_mac_csr(UINT8 reg) +{ + while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + smc911x_reg_write(MAC_CSR_CMD, (MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg)); + while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + return smc911x_reg_read(MAC_CSR_DATA); +} + +VOID smc911x_set_mac_csr(UINT8 reg, UINT32 data) +{ + while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + smc911x_reg_write(MAC_CSR_DATA, data); + smc911x_reg_write(MAC_CSR_CMD, (MAC_CSR_CMD_CSR_BUSY | reg)); + while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; +} + +VOID smc911x_reset(VOID) +{ + INT32 timeout; + + /* Take out of PM setting first */ + if (smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY) { + /* Write to the bytetest will take out of powerdown */ + smc911x_reg_write(BYTE_TEST, 0x0); + + timeout = 10; + + while (timeout-- && !(smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY)) + MicroSecondDelay(10); + if (!timeout) { + DEBUG((EFI_D_ERROR, "smc911x_reset: timeout waiting for PM restore\n")); + return; + } + } + + /* Disable interrupts */ + smc911x_reg_write(INT_EN, 0); + + smc911x_reg_write(HW_CFG, HW_CFG_SRST); + + timeout = 1000; + while (timeout-- && (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)) + MicroSecondDelay(10); + + if (!timeout) { + DEBUG((EFI_D_ERROR, "smc911x_reset: reset timeout\n")); + return; + } + + /* Reset the FIFO level and flow control settings */ + smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN); + smc911x_reg_write(AFC_CFG, 0x0050287F); + + /* Set to LED outputs */ + smc911x_reg_write(GPIO_CFG, 0x70070000); +} + +VOID smc911x_phy_reset(VOID) +{ + UINT32 reg; + + reg = smc911x_reg_read(PMT_CTRL); + reg &= ~0xfffff030; + reg |= PMT_CTRL_PHY_RST; + smc911x_reg_write(PMT_CTRL, reg); + + MicroSecondDelay(100000); +} + +VOID smc911x_miiphy_read(UINT8 phy, UINT8 reg, UINT16 *val) +{ + while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + ; + + smc911x_set_mac_csr(MII_ACC, (phy << 11 | reg << 6 | MII_ACC_MII_BUSY)); + + while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + ; + + *val = smc911x_get_mac_csr(MII_DATA); +} + +VOID smc911x_miiphy_write(UINT8 phy, UINT8 reg, UINT16 val) +{ + while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + ; + + smc911x_set_mac_csr(MII_DATA, val); + smc911x_set_mac_csr(MII_ACC, (phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE)); + + while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + ; +} + +VOID smc911x_phy_configure(VOID) +{ + INT32 timeout; + UINT16 status; + + smc911x_phy_reset(); + + smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET); + MicroSecondDelay(1000); + smc911x_miiphy_write(1, PHY_ANAR, 0x01e1); + smc911x_miiphy_write(1, PHY_BMCR, (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG)); + + timeout = 5000; + do { + MicroSecondDelay(1000); + if ((timeout--) == 0) + goto err_out; + + smc911x_miiphy_read(1, PHY_BMSR, &status); + } while (!(status & PHY_BMSR_LS)); + + DEBUG((EFI_D_ERROR, "smc911x_phy_configure: PHY initialized\n")); + + return; + +err_out: + DEBUG((EFI_D_ERROR, "smc911x_phy_configure: autonegotiation timed out\n")); +} + +VOID smc911x_handle_mac_address(ETH_DXE_PRIVATE_DATA *Private) +{ + UINT32 addrh, addrl; + + addrl = Private->Mode.CurrentAddress.Addr[0] | \ + (Private->Mode.CurrentAddress.Addr[1] << 8) | \ + (Private->Mode.CurrentAddress.Addr[2] << 16) | \ + (Private->Mode.CurrentAddress.Addr[3] << 24); + addrh = Private->Mode.CurrentAddress.Addr[4] | \ + (Private->Mode.CurrentAddress.Addr[5] << 8); + + smc911x_set_mac_csr(ADDRL, addrl); + smc911x_set_mac_csr(ADDRH, addrh); +} + +VOID smc911x_enable(VOID) +{ + /* Enable TX */ + smc911x_reg_write(HW_CFG, (8 << 16 | HW_CFG_SF)); + + smc911x_reg_write(GPT_CFG, (GPT_CFG_TIMER_EN | 10000)); + + smc911x_reg_write(TX_CFG, TX_CFG_TX_ON); + + /* no padding to start of packets */ + smc911x_reg_write(RX_CFG, 0); + + smc911x_set_mac_csr(MAC_CR, (MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS /*| MAC_CR_PADSTR*/)); +} + +EFI_STATUS +EFIAPI +EthStart( + EFI_SIMPLE_NETWORK_PROTOCOL *This +) +{ + ETH_DXE_PRIVATE_DATA *Private; + + Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This); + + switch ( Private->Snp.Mode->State ) + { + case EfiSimpleNetworkStopped: + break; + + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + return( EFI_ALREADY_STARTED ); + break; + + default: + return( EFI_DEVICE_ERROR ); + break; + } + + /* gpio configuration */ + MmioAndThenOr32(0x11000000 + 0x120, ~((0xFF<<16)|(0xFF<<4)), ((0x22<<16)|(0x52<<4))); + + /* 16 Bit bus width */ + MmioWrite32(0x11000000 + 0x1C0, 0x22222222); + MmioWrite32(0x11000000 + 0x1E0, 0x22222222); + + /* SROM BANK1 */ + MmioAndThenOr32(0x12570000, ~(0xF<<4), (((1<<0)|(0<<2)|(1<<3))<<4)); + + /* set timing for nCS1 suitable for ethernet chip */ + MmioWrite32(0x12570008, ((0x1 << 0) | (0x9 << 4) | (0xC << 8) | (0x1 << 12) | \ + (0x6 << 16) | (0x1 << 24) | (0x1 << 28))); + + Private->Snp.Mode->State = EfiSimpleNetworkStarted; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +EthStop( + EFI_SIMPLE_NETWORK_PROTOCOL *This +) +{ + ETH_DXE_PRIVATE_DATA *Private; + + Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This); + + switch ( Private->Snp.Mode->State ) + { + case EfiSimpleNetworkStarted: + break; + + case EfiSimpleNetworkStopped: + return( EFI_NOT_STARTED ); + break; + + default: + return( EFI_DEVICE_ERROR ); + break; + } + + Private->Snp.Mode->State = EfiSimpleNetworkStopped; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +EthInitialize( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINTN ExtraRxBufferSize, + UINTN ExtraTxBufferSize +) +{ + UINT32 val, i, addrh, addrl; + ETH_DXE_PRIVATE_DATA *Private; + + Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This); + + switch ( Private->Snp.Mode->State ) + { + case EfiSimpleNetworkStarted: + break; + + case EfiSimpleNetworkStopped: + return( EFI_NOT_STARTED ); + break; + + default: + return( EFI_DEVICE_ERROR ); + break; + } + + val = smc911x_reg_read(BYTE_TEST); + + if(val == 0xFFFFFFFF) { + return EFI_NO_MEDIA; + } + else if(val != 0x87654321) { + DEBUG((EFI_D_ERROR,"EthInitialize: Invalid chip endian 0x%x\n", val)); + return EFI_NO_MEDIA; + } + + val = smc911x_reg_read(ID_REV) >> 16; + for(i=0;chip_ids[i].id != 0;i++) { + if(chip_ids[i].id == val) + break; + } + + if(!chip_ids[i].id) { + DEBUG((EFI_D_ERROR,"EthInitialize: Unknown chip id 0x%x\n", val)); + return EFI_NO_MEDIA; + } + else { + DEBUG((EFI_D_ERROR,"EthInitialize: Chip id 0x%x\n", val)); + } + + addrh = smc911x_get_mac_csr(ADDRH); + addrl = smc911x_get_mac_csr(ADDRL); + + if (addrl == 0xffffffff && addrh == 0x0000ffff) { + addrh = 0x00000040; + addrl = 0x5c260a5b; + } + + Private->Mode.CurrentAddress.Addr[0] = (addrl & 0xFF); + Private->Mode.CurrentAddress.Addr[1] = (addrl & 0xFF00)>>8; + Private->Mode.CurrentAddress.Addr[2] = (addrl & 0xFF0000)>>16; + Private->Mode.CurrentAddress.Addr[3] = (addrl & 0xFF000000)>>24; + Private->Mode.CurrentAddress.Addr[4] = (addrh & 0xFF); + Private->Mode.CurrentAddress.Addr[5] = (addrh & 0xFF00)>>8; + gBS->CopyMem((VOID *)&Private->Mode.PermanentAddress, \ + (VOID *)&Private->Mode.CurrentAddress, \ + sizeof(EFI_MAC_ADDRESS)); + + DEBUG((EFI_D_ERROR,"EthInitialize: MAC address is ")); + + for(i=6;i>0;i--) { + DEBUG((EFI_D_ERROR,"%02x", Private->Mode.CurrentAddress.Addr[i - 1])); + if(i > 1) + DEBUG((EFI_D_ERROR,":")); + else + DEBUG((EFI_D_ERROR,"\n")); + } + + smc911x_reset(); + + /* Configure the PHY, initialize the link state */ + smc911x_phy_configure(); + + smc911x_handle_mac_address(Private); + + /* Turn on Tx + Rx */ + smc911x_enable(); + + Private->Snp.Mode->State = EfiSimpleNetworkInitialized; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +EthReset( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN ExtendedVerification +) +{ + ETH_DXE_PRIVATE_DATA *Private; + + Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This); + + switch ( Private->Snp.Mode->State ) + { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return( EFI_NOT_STARTED ); + break; + + default: + return( EFI_DEVICE_ERROR ); + break; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +EthShutdown( + EFI_SIMPLE_NETWORK_PROTOCOL *This +) +{ + ETH_DXE_PRIVATE_DATA *Private; + + Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This); + + switch ( Private->Snp.Mode->State ) + { + case EfiSimpleNetworkInitialized: + break; + + case EfiSimpleNetworkStopped: + return( EFI_NOT_STARTED ); + break; + + default: + return( EFI_DEVICE_ERROR ); + break; + } + + Private->Snp.Mode->State = EfiSimpleNetworkStarted; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +EthReceiveFilters( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINT32 Enable, + UINT32 Disable, + BOOLEAN ResetMCastFilter, + UINTN MCastFilterCnt, + EFI_MAC_ADDRESS *MCastFilter +) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +EthStationAddress( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN Reset, + EFI_MAC_ADDRESS *New +) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +EthStatistics( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN Reset, + UINTN *StatisticsSize, + EFI_NETWORK_STATISTICS *StatisticsTable +) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +EthMCastIpToMac( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN IPv6, + EFI_IP_ADDRESS *IP, + EFI_MAC_ADDRESS *MAC +) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +EthNvData( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN ReadWrite, + UINTN Offset, + UINTN BufferSize, + VOID *Buffer +) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +EthGetStatus( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINT32 *InterruptStatus, + VOID **TxBuf +) +{ + if ( TxBuf != NULL ) { + *( ( UINT8 ** ) TxBuf ) = ( UINT8 * ) 1; + } + + if ( InterruptStatus != NULL ) { + *InterruptStatus = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +EthTransmit( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINTN HeaderSize, + UINTN BufferSize, + VOID *Buffer, + EFI_MAC_ADDRESS *SrcAddr, + EFI_MAC_ADDRESS *DestAddr, + UINT16 *Protocol +) +{ + UINT32 *data = (UINT32 *)Buffer; + UINT32 tmpSize; + UINT32 status; + EthernetHeader *EnetHeader; + + if ( This->Mode->State < EfiSimpleNetworkStarted ) { + return( EFI_NOT_STARTED ); + } + + if ( HeaderSize != 0 ) { + if ( ( DestAddr == NULL ) || ( Protocol == NULL ) || \ + ( HeaderSize != This->Mode->MediaHeaderSize ) ) { + return( EFI_INVALID_PARAMETER ); + } + + if ( SrcAddr == NULL ) { + SrcAddr = &This->Mode->CurrentAddress; + } + + EnetHeader = (EthernetHeader *)Buffer; + + CopyMem( EnetHeader->DstAddr, DestAddr, NET_ETHER_ADDR_LEN ); + CopyMem( EnetHeader->SrcAddr, SrcAddr, NET_ETHER_ADDR_LEN ); + + EnetHeader->Type = HTONS( *Protocol ); + } + + smc911x_reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | BufferSize); + smc911x_reg_write(TX_DATA_FIFO, BufferSize); + + tmpSize = (BufferSize + 3) / 4; + + while (tmpSize--) + smc911x_reg_write(TX_DATA_FIFO, *data++); + + /* wait for transmission */ + while (!((smc911x_reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16)) + ; + + /* get status. Ignore 'no carrier' error, it has no meaning for + * full duplex operation + */ + status = smc911x_reg_read(TX_STATUS_FIFO) & \ + (TX_STS_LOC | TX_STS_LATE_COLL | \ + TX_STS_MANY_COLL | TX_STS_MANY_DEFER | \ + TX_STS_UNDERRUN); + + if (!status) + return EFI_SUCCESS; + + DEBUG((EFI_D_ERROR, "EthTransmit: Failed to send packet: %s%s%s%s%s\n", + status & TX_STS_LOC ? "TX_STS_LOC " : "", + status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "", + status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "", + status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "", + status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : "")); + + return EFI_DEVICE_ERROR; +} + +EFI_STATUS +EFIAPI +EthReceive( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINTN *HeaderSize, + UINTN *BufferSize, + VOID *Buffer, + EFI_MAC_ADDRESS *SrcAddr, + EFI_MAC_ADDRESS *DestAddr, + UINT16 *Protocol +) +{ + UINT32 *data = (UINT32 *)Buffer; + UINT32 pktSize, tmpSize; + UINT32 status, i; + EthernetHeader *EnetHeader; + + /* workaround: delay for rx packet should be added here. + * because NetLoop does not guarantee the RX packet delay. + */ + for (i=0; i<0x100000; i++) { + if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) + break; + } + + if (i == 0x100000) { + DEBUG((EFI_D_ERROR, "EthReceive: timeout in RX\n")); + return EFI_TIMEOUT; + } + + if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { + status = smc911x_reg_read(RX_STATUS_FIFO); + pktSize = (status & RX_STS_PKT_LEN) >> 16; + + smc911x_reg_write(RX_CFG, 0); + + tmpSize = (pktSize + 3) / 4; + i = 0; + while (tmpSize--) + *data++ = smc911x_reg_read(RX_DATA_FIFO); + + if (status & RX_STS_ES) { + DEBUG((EFI_D_ERROR, "EthReceive: dropped bad packet. Status: 0x%x\n", status)); + } + + *BufferSize = pktSize -4; //discard 4 bytes of FCS + + } + +#if 0 + { + UINT8 *tmpBuffer = (UINT8 *)Buffer; + + for(i=0;i<*BufferSize;i++) { + DEBUG((EFI_D_ERROR, "%02x", *tmpBuffer++)); + if((i%16) < 15) + DEBUG((EFI_D_ERROR, " ")); + else + DEBUG((EFI_D_ERROR, "\n")); + } + + DEBUG((EFI_D_ERROR, "\n")); + } +#endif + + if(HeaderSize != NULL) { + *HeaderSize = sizeof(EthernetHeader); + } + + EnetHeader = (EthernetHeader *)Buffer; + + if(SrcAddr != NULL) { + ZeroMem(SrcAddr, sizeof(EFI_MAC_ADDRESS)); + CopyMem(SrcAddr, EnetHeader->SrcAddr, NET_ETHER_ADDR_LEN); + } + + if(DestAddr != NULL) { + ZeroMem(DestAddr, sizeof(EFI_MAC_ADDRESS)); + CopyMem(DestAddr, EnetHeader->DstAddr, NET_ETHER_ADDR_LEN); + } + + if (Protocol != NULL) { + *Protocol = NTOHS(EnetHeader->Type); + } + + return EFI_SUCCESS; +} + + +/** + Initialize the state information for the Display Dxe + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +EthDxeInitialize ( + EFI_HANDLE ImageHandle, + EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_GUID SimpleNetworkProtocolGuid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; + EFI_GUID DevicePathProtocolGuid = EFI_DEVICE_PATH_PROTOCOL_GUID; + ETH_DXE_PRIVATE_DATA *Private; + + /* Allocate the private data */ + Private = (ETH_DXE_PRIVATE_DATA *)AllocateCopyPool(sizeof(ETH_DXE_PRIVATE_DATA), &gEthDxePrivateTemplate ); + if ( Private == NULL ) { + Status = EFI_OUT_OF_RESOURCES; + ASSERT_EFI_ERROR(Status); + } + + Private->Snp.Mode = &Private->Mode; + + /* Set the broadcast address */ + SetMem( &Private->Mode.BroadcastAddress, sizeof( EFI_MAC_ADDRESS ), 0xFF ); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &DevicePathProtocolGuid, + &Private->DevicePath, + &SimpleNetworkProtocolGuid, + &Private->Snp, + NULL); + + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.h new file mode 100644 index 000000000..3b9a790eb --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.h @@ -0,0 +1,612 @@ +/** @file +* +* Copyright (c) 2012, Samsung Electronics Co. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + + +#ifndef _EthDxe_H__ +#define _EthDxe_H__ + +#define NET_ETHER_HEADER_SIZE 14 + +typedef struct +{ + UINT8 DstAddr[ NET_ETHER_ADDR_LEN ]; + UINT8 SrcAddr[ NET_ETHER_ADDR_LEN ]; + UINT16 Type; +} EthernetHeader; + +/* Chip ID values */ +#define CHIP_9115 0x115 +#define CHIP_9116 0x116 +#define CHIP_9117 0x117 +#define CHIP_9118 0x118 +#define CHIP_9211 0x9211 +#define CHIP_9215 0x115a +#define CHIP_9216 0x116a +#define CHIP_9217 0x117a +#define CHIP_9218 0x118a +#define CHIP_9220 0x9220 +#define CHIP_9221 0x9221 + +struct chip_id { + UINT16 id; + CHAR8 *name; +}; + +static const struct chip_id chip_ids[] = { + { CHIP_9115, "LAN9115" }, + { CHIP_9116, "LAN9116" }, + { CHIP_9117, "LAN9117" }, + { CHIP_9118, "LAN9118" }, + { CHIP_9211, "LAN9211" }, + { CHIP_9215, "LAN9215" }, + { CHIP_9216, "LAN9216" }, + { CHIP_9217, "LAN9217" }, + { CHIP_9218, "LAN9218" }, + { CHIP_9220, "LAN9220" }, + { CHIP_9221, "LAN9221" }, + { 0, NULL }, +}; + + +/* Below are the register offsets and bit definitions + * of the Lan911x memory space + */ +#define RX_DATA_FIFO 0x00 + +#define TX_DATA_FIFO 0x20 +#define TX_CMD_A_INT_ON_COMP 0x80000000 +#define TX_CMD_A_INT_BUF_END_ALGN 0x03000000 +#define TX_CMD_A_INT_4_BYTE_ALGN 0x00000000 +#define TX_CMD_A_INT_16_BYTE_ALGN 0x01000000 +#define TX_CMD_A_INT_32_BYTE_ALGN 0x02000000 +#define TX_CMD_A_INT_DATA_OFFSET 0x001F0000 +#define TX_CMD_A_INT_FIRST_SEG 0x00002000 +#define TX_CMD_A_INT_LAST_SEG 0x00001000 +#define TX_CMD_A_BUF_SIZE 0x000007FF +#define TX_CMD_B_PKT_TAG 0xFFFF0000 +#define TX_CMD_B_ADD_CRC_DISABLE 0x00002000 +#define TX_CMD_B_DISABLE_PADDING 0x00001000 +#define TX_CMD_B_PKT_BYTE_LENGTH 0x000007FF + +#define RX_STATUS_FIFO 0x40 +#define RX_STS_PKT_LEN 0x3FFF0000 +#define RX_STS_ES 0x00008000 +#define RX_STS_BCST 0x00002000 +#define RX_STS_LEN_ERR 0x00001000 +#define RX_STS_RUNT_ERR 0x00000800 +#define RX_STS_MCAST 0x00000400 +#define RX_STS_TOO_LONG 0x00000080 +#define RX_STS_COLL 0x00000040 +#define RX_STS_ETH_TYPE 0x00000020 +#define RX_STS_WDOG_TMT 0x00000010 +#define RX_STS_MII_ERR 0x00000008 +#define RX_STS_DRIBBLING 0x00000004 +#define RX_STS_CRC_ERR 0x00000002 +#define RX_STATUS_FIFO_PEEK 0x44 +#define TX_STATUS_FIFO 0x48 +#define TX_STS_TAG 0xFFFF0000 +#define TX_STS_ES 0x00008000 +#define TX_STS_LOC 0x00000800 +#define TX_STS_NO_CARR 0x00000400 +#define TX_STS_LATE_COLL 0x00000200 +#define TX_STS_MANY_COLL 0x00000100 +#define TX_STS_COLL_CNT 0x00000078 +#define TX_STS_MANY_DEFER 0x00000004 +#define TX_STS_UNDERRUN 0x00000002 +#define TX_STS_DEFERRED 0x00000001 +#define TX_STATUS_FIFO_PEEK 0x4C +#define ID_REV 0x50 +#define ID_REV_CHIP_ID 0xFFFF0000 /* RO */ +#define ID_REV_REV_ID 0x0000FFFF /* RO */ + +#define INT_CFG 0x54 +#define INT_CFG_INT_DEAS 0xFF000000 /* R/W */ +#define INT_CFG_INT_DEAS_CLR 0x00004000 +#define INT_CFG_INT_DEAS_STS 0x00002000 +#define INT_CFG_IRQ_INT 0x00001000 /* RO */ +#define INT_CFG_IRQ_EN 0x00000100 /* R/W */ + /* R/W Not Affected by SW Reset */ +#define INT_CFG_IRQ_POL 0x00000010 + /* R/W Not Affected by SW Reset */ +#define INT_CFG_IRQ_TYPE 0x00000001 + +#define INT_STS 0x58 +#define INT_STS_SW_INT 0x80000000 /* R/WC */ +#define INT_STS_TXSTOP_INT 0x02000000 /* R/WC */ +#define INT_STS_RXSTOP_INT 0x01000000 /* R/WC */ +#define INT_STS_RXDFH_INT 0x00800000 /* R/WC */ +#define INT_STS_RXDF_INT 0x00400000 /* R/WC */ +#define INT_STS_TX_IOC 0x00200000 /* R/WC */ +#define INT_STS_RXD_INT 0x00100000 /* R/WC */ +#define INT_STS_GPT_INT 0x00080000 /* R/WC */ +#define INT_STS_PHY_INT 0x00040000 /* RO */ +#define INT_STS_PME_INT 0x00020000 /* R/WC */ +#define INT_STS_TXSO 0x00010000 /* R/WC */ +#define INT_STS_RWT 0x00008000 /* R/WC */ +#define INT_STS_RXE 0x00004000 /* R/WC */ +#define INT_STS_TXE 0x00002000 /* R/WC */ +/*#define INT_STS_ERX 0x00001000*/ /* R/WC */ +#define INT_STS_TDFU 0x00000800 /* R/WC */ +#define INT_STS_TDFO 0x00000400 /* R/WC */ +#define INT_STS_TDFA 0x00000200 /* R/WC */ +#define INT_STS_TSFF 0x00000100 /* R/WC */ +#define INT_STS_TSFL 0x00000080 /* R/WC */ +/*#define INT_STS_RXDF 0x00000040*/ /* R/WC */ +#define INT_STS_RDFO 0x00000040 /* R/WC */ +#define INT_STS_RDFL 0x00000020 /* R/WC */ +#define INT_STS_RSFF 0x00000010 /* R/WC */ +#define INT_STS_RSFL 0x00000008 /* R/WC */ +#define INT_STS_GPIO2_INT 0x00000004 /* R/WC */ +#define INT_STS_GPIO1_INT 0x00000002 /* R/WC */ +#define INT_STS_GPIO0_INT 0x00000001 /* R/WC */ +#define INT_EN 0x5C +#define INT_EN_SW_INT_EN 0x80000000 /* R/W */ +#define INT_EN_TXSTOP_INT_EN 0x02000000 /* R/W */ +#define INT_EN_RXSTOP_INT_EN 0x01000000 /* R/W */ +#define INT_EN_RXDFH_INT_EN 0x00800000 /* R/W */ +/*#define INT_EN_RXDF_INT_EN 0x00400000*/ /* R/W */ +#define INT_EN_TIOC_INT_EN 0x00200000 /* R/W */ +#define INT_EN_RXD_INT_EN 0x00100000 /* R/W */ +#define INT_EN_GPT_INT_EN 0x00080000 /* R/W */ +#define INT_EN_PHY_INT_EN 0x00040000 /* R/W */ +#define INT_EN_PME_INT_EN 0x00020000 /* R/W */ +#define INT_EN_TXSO_EN 0x00010000 /* R/W */ +#define INT_EN_RWT_EN 0x00008000 /* R/W */ +#define INT_EN_RXE_EN 0x00004000 /* R/W */ +#define INT_EN_TXE_EN 0x00002000 /* R/W */ +/*#define INT_EN_ERX_EN 0x00001000*/ /* R/W */ +#define INT_EN_TDFU_EN 0x00000800 /* R/W */ +#define INT_EN_TDFO_EN 0x00000400 /* R/W */ +#define INT_EN_TDFA_EN 0x00000200 /* R/W */ +#define INT_EN_TSFF_EN 0x00000100 /* R/W */ +#define INT_EN_TSFL_EN 0x00000080 /* R/W */ +/*#define INT_EN_RXDF_EN 0x00000040*/ /* R/W */ +#define INT_EN_RDFO_EN 0x00000040 /* R/W */ +#define INT_EN_RDFL_EN 0x00000020 /* R/W */ +#define INT_EN_RSFF_EN 0x00000010 /* R/W */ +#define INT_EN_RSFL_EN 0x00000008 /* R/W */ +#define INT_EN_GPIO2_INT 0x00000004 /* R/W */ +#define INT_EN_GPIO1_INT 0x00000002 /* R/W */ +#define INT_EN_GPIO0_INT 0x00000001 /* R/W */ + +#define BYTE_TEST 0x64 +#define FIFO_INT 0x68 +#define FIFO_INT_TX_AVAIL_LEVEL 0xFF000000 /* R/W */ +#define FIFO_INT_TX_STS_LEVEL 0x00FF0000 /* R/W */ +#define FIFO_INT_RX_AVAIL_LEVEL 0x0000FF00 /* R/W */ +#define FIFO_INT_RX_STS_LEVEL 0x000000FF /* R/W */ + +#define RX_CFG 0x6C +#define RX_CFG_RX_END_ALGN 0xC0000000 /* R/W */ +#define RX_CFG_RX_END_ALGN4 0x00000000 /* R/W */ +#define RX_CFG_RX_END_ALGN16 0x40000000 /* R/W */ +#define RX_CFG_RX_END_ALGN32 0x80000000 /* R/W */ +#define RX_CFG_RX_DMA_CNT 0x0FFF0000 /* R/W */ +#define RX_CFG_RX_DUMP 0x00008000 /* R/W */ +#define RX_CFG_RXDOFF 0x00001F00 /* R/W */ +/*#define RX_CFG_RXBAD 0x00000001*/ /* R/W */ + +#define TX_CFG 0x70 +/*#define TX_CFG_TX_DMA_LVL 0xE0000000*/ /* R/W */ + /* R/W Self Clearing */ +/*#define TX_CFG_TX_DMA_CNT 0x0FFF0000*/ +#define TX_CFG_TXS_DUMP 0x00008000 /* Self Clearing */ +#define TX_CFG_TXD_DUMP 0x00004000 /* Self Clearing */ +#define TX_CFG_TXSAO 0x00000004 /* R/W */ +#define TX_CFG_TX_ON 0x00000002 /* R/W */ +#define TX_CFG_STOP_TX 0x00000001 /* Self Clearing */ + +#define HW_CFG 0x74 +#define HW_CFG_TTM 0x00200000 /* R/W */ +#define HW_CFG_SF 0x00100000 /* R/W */ +#define HW_CFG_TX_FIF_SZ 0x000F0000 /* R/W */ +#define HW_CFG_TR 0x00003000 /* R/W */ +#define HW_CFG_PHY_CLK_SEL 0x00000060 /* R/W */ +#define HW_CFG_PHY_CLK_SEL_INT_PHY 0x00000000 /* R/W */ +#define HW_CFG_PHY_CLK_SEL_EXT_PHY 0x00000020 /* R/W */ +#define HW_CFG_PHY_CLK_SEL_CLK_DIS 0x00000040 /* R/W */ +#define HW_CFG_SMI_SEL 0x00000010 /* R/W */ +#define HW_CFG_EXT_PHY_DET 0x00000008 /* RO */ +#define HW_CFG_EXT_PHY_EN 0x00000004 /* R/W */ +#define HW_CFG_32_16_BIT_MODE 0x00000004 /* RO */ +#define HW_CFG_SRST_TO 0x00000002 /* RO */ +#define HW_CFG_SRST 0x00000001 /* Self Clearing */ + +#define RX_DP_CTRL 0x78 +#define RX_DP_CTRL_RX_FFWD 0x80000000 /* R/W */ +#define RX_DP_CTRL_FFWD_BUSY 0x80000000 /* RO */ + +#define RX_FIFO_INF 0x7C +#define RX_FIFO_INF_RXSUSED 0x00FF0000 /* RO */ +#define RX_FIFO_INF_RXDUSED 0x0000FFFF /* RO */ + +#define TX_FIFO_INF 0x80 +#define TX_FIFO_INF_TSUSED 0x00FF0000 /* RO */ +#define TX_FIFO_INF_TDFREE 0x0000FFFF /* RO */ + +#define PMT_CTRL 0x84 +#define PMT_CTRL_PM_MODE 0x00003000 /* Self Clearing */ +#define PMT_CTRL_PHY_RST 0x00000400 /* Self Clearing */ +#define PMT_CTRL_WOL_EN 0x00000200 /* R/W */ +#define PMT_CTRL_ED_EN 0x00000100 /* R/W */ + /* R/W Not Affected by SW Reset */ +#define PMT_CTRL_PME_TYPE 0x00000040 +#define PMT_CTRL_WUPS 0x00000030 /* R/WC */ +#define PMT_CTRL_WUPS_NOWAKE 0x00000000 /* R/WC */ +#define PMT_CTRL_WUPS_ED 0x00000010 /* R/WC */ +#define PMT_CTRL_WUPS_WOL 0x00000020 /* R/WC */ +#define PMT_CTRL_WUPS_MULTI 0x00000030 /* R/WC */ +#define PMT_CTRL_PME_IND 0x00000008 /* R/W */ +#define PMT_CTRL_PME_POL 0x00000004 /* R/W */ + /* R/W Not Affected by SW Reset */ +#define PMT_CTRL_PME_EN 0x00000002 +#define PMT_CTRL_READY 0x00000001 /* RO */ + +#define GPIO_CFG 0x88 +#define GPIO_CFG_LED3_EN 0x40000000 /* R/W */ +#define GPIO_CFG_LED2_EN 0x20000000 /* R/W */ +#define GPIO_CFG_LED1_EN 0x10000000 /* R/W */ +#define GPIO_CFG_GPIO2_INT_POL 0x04000000 /* R/W */ +#define GPIO_CFG_GPIO1_INT_POL 0x02000000 /* R/W */ +#define GPIO_CFG_GPIO0_INT_POL 0x01000000 /* R/W */ +#define GPIO_CFG_EEPR_EN 0x00700000 /* R/W */ +#define GPIO_CFG_GPIOBUF2 0x00040000 /* R/W */ +#define GPIO_CFG_GPIOBUF1 0x00020000 /* R/W */ +#define GPIO_CFG_GPIOBUF0 0x00010000 /* R/W */ +#define GPIO_CFG_GPIODIR2 0x00000400 /* R/W */ +#define GPIO_CFG_GPIODIR1 0x00000200 /* R/W */ +#define GPIO_CFG_GPIODIR0 0x00000100 /* R/W */ +#define GPIO_CFG_GPIOD4 0x00000010 /* R/W */ +#define GPIO_CFG_GPIOD3 0x00000008 /* R/W */ +#define GPIO_CFG_GPIOD2 0x00000004 /* R/W */ +#define GPIO_CFG_GPIOD1 0x00000002 /* R/W */ +#define GPIO_CFG_GPIOD0 0x00000001 /* R/W */ + +#define GPT_CFG 0x8C +#define GPT_CFG_TIMER_EN 0x20000000 /* R/W */ +#define GPT_CFG_GPT_LOAD 0x0000FFFF /* R/W */ + +#define GPT_CNT 0x90 +#define GPT_CNT_GPT_CNT 0x0000FFFF /* RO */ + +#define ENDIAN 0x98 +#define FREE_RUN 0x9C +#define RX_DROP 0xA0 +#define MAC_CSR_CMD 0xA4 +#define MAC_CSR_CMD_CSR_BUSY 0x80000000 /* Self Clearing */ +#define MAC_CSR_CMD_R_NOT_W 0x40000000 /* R/W */ +#define MAC_CSR_CMD_CSR_ADDR 0x000000FF /* R/W */ + +#define MAC_CSR_DATA 0xA8 +#define AFC_CFG 0xAC +#define AFC_CFG_AFC_HI 0x00FF0000 /* R/W */ +#define AFC_CFG_AFC_LO 0x0000FF00 /* R/W */ +#define AFC_CFG_BACK_DUR 0x000000F0 /* R/W */ +#define AFC_CFG_FCMULT 0x00000008 /* R/W */ +#define AFC_CFG_FCBRD 0x00000004 /* R/W */ +#define AFC_CFG_FCADD 0x00000002 /* R/W */ +#define AFC_CFG_FCANY 0x00000001 /* R/W */ + +#define E2P_CMD 0xB0 +#define E2P_CMD_EPC_BUSY 0x80000000 /* Self Clearing */ +#define E2P_CMD_EPC_CMD 0x70000000 /* R/W */ +#define E2P_CMD_EPC_CMD_READ 0x00000000 /* R/W */ +#define E2P_CMD_EPC_CMD_EWDS 0x10000000 /* R/W */ +#define E2P_CMD_EPC_CMD_EWEN 0x20000000 /* R/W */ +#define E2P_CMD_EPC_CMD_WRITE 0x30000000 /* R/W */ +#define E2P_CMD_EPC_CMD_WRAL 0x40000000 /* R/W */ +#define E2P_CMD_EPC_CMD_ERASE 0x50000000 /* R/W */ +#define E2P_CMD_EPC_CMD_ERAL 0x60000000 /* R/W */ +#define E2P_CMD_EPC_CMD_RELOAD 0x70000000 /* R/W */ +#define E2P_CMD_EPC_TIMEOUT 0x00000200 /* RO */ +#define E2P_CMD_MAC_ADDR_LOADED 0x00000100 /* RO */ +#define E2P_CMD_EPC_ADDR 0x000000FF /* R/W */ + +#define E2P_DATA 0xB4 +#define E2P_DATA_EEPROM_DATA 0x000000FF /* R/W */ +/* end of LAN register offsets and bit definitions */ + +/* MAC Control and Status registers */ +#define MAC_CR 0x01 /* R/W */ + +/* MAC_CR - MAC Control Register */ +#define MAC_CR_RXALL 0x80000000 +/* TODO: delete this bit? It is not described in the data sheet. */ +#define MAC_CR_HBDIS 0x10000000 +#define MAC_CR_RCVOWN 0x00800000 +#define MAC_CR_LOOPBK 0x00200000 +#define MAC_CR_FDPX 0x00100000 +#define MAC_CR_MCPAS 0x00080000 +#define MAC_CR_PRMS 0x00040000 +#define MAC_CR_INVFILT 0x00020000 +#define MAC_CR_PASSBAD 0x00010000 +#define MAC_CR_HFILT 0x00008000 +#define MAC_CR_HPFILT 0x00002000 +#define MAC_CR_LCOLL 0x00001000 +#define MAC_CR_BCAST 0x00000800 +#define MAC_CR_DISRTY 0x00000400 +#define MAC_CR_PADSTR 0x00000100 +#define MAC_CR_BOLMT_MASK 0x000000C0 +#define MAC_CR_DFCHK 0x00000020 +#define MAC_CR_TXEN 0x00000008 +#define MAC_CR_RXEN 0x00000004 + +#define ADDRH 0x02 /* R/W mask 0x0000FFFFUL */ +#define ADDRL 0x03 /* R/W mask 0xFFFFFFFFUL */ +#define HASHH 0x04 /* R/W */ +#define HASHL 0x05 /* R/W */ + +#define MII_ACC 0x06 /* R/W */ +#define MII_ACC_PHY_ADDR 0x0000F800 +#define MII_ACC_MIIRINDA 0x000007C0 +#define MII_ACC_MII_WRITE 0x00000002 +#define MII_ACC_MII_BUSY 0x00000001 + +#define MII_DATA 0x07 /* R/W mask 0x0000FFFFUL */ + +#define FLOW 0x08 /* R/W */ +#define FLOW_FCPT 0xFFFF0000 +#define FLOW_FCPASS 0x00000004 +#define FLOW_FCEN 0x00000002 +#define FLOW_FCBSY 0x00000001 + +#define VLAN1 0x09 /* R/W mask 0x0000FFFFUL */ +#define VLAN1_VTI1 0x0000ffff + +#define VLAN2 0x0A /* R/W mask 0x0000FFFFUL */ +#define VLAN2_VTI2 0x0000ffff + +#define WUFF 0x0B /* WO */ + +#define WUCSR 0x0C /* R/W */ +#define WUCSR_GUE 0x00000200 +#define WUCSR_WUFR 0x00000040 +#define WUCSR_MPR 0x00000020 +#define WUCSR_WAKE_EN 0x00000004 +#define WUCSR_MPEN 0x00000002 + +/* phy register offsets */ +#define PHY_BMCR 0x00 +#define PHY_BMSR 0x01 +#define PHY_PHYIDR1 0x02 +#define PHY_PHYIDR2 0x03 +#define PHY_ANAR 0x04 +#define PHY_ANLPAR 0x05 +#define PHY_ANER 0x06 +#define PHY_ANNPTR 0x07 +#define PHY_ANLPNP 0x08 +#define PHY_1000BTCR 0x09 +#define PHY_1000BTSR 0x0A +#define PHY_EXSR 0x0F +#define PHY_PHYSTS 0x10 +#define PHY_MIPSCR 0x11 +#define PHY_MIPGSR 0x12 +#define PHY_DCR 0x13 +#define PHY_FCSCR 0x14 +#define PHY_RECR 0x15 +#define PHY_PCSR 0x16 +#define PHY_LBR 0x17 +#define PHY_10BTSCR 0x18 +#define PHY_PHYCTRL 0x19 + +/* PHY BMCR */ +#define PHY_BMCR_RESET 0x8000 +#define PHY_BMCR_LOOP 0x4000 +#define PHY_BMCR_100MB 0x2000 +#define PHY_BMCR_AUTON 0x1000 +#define PHY_BMCR_POWD 0x0800 +#define PHY_BMCR_ISO 0x0400 +#define PHY_BMCR_RST_NEG 0x0200 +#define PHY_BMCR_DPLX 0x0100 +#define PHY_BMCR_COL_TST 0x0080 + +#define PHY_BMCR_SPEED_MASK 0x2040 +#define PHY_BMCR_1000_MBPS 0x0040 +#define PHY_BMCR_100_MBPS 0x2000 +#define PHY_BMCR_10_MBPS 0x0000 + +/* phy BMSR */ +#define PHY_BMSR_100T4 0x8000 +#define PHY_BMSR_100TXF 0x4000 +#define PHY_BMSR_100TXH 0x2000 +#define PHY_BMSR_10TF 0x1000 +#define PHY_BMSR_10TH 0x0800 +#define PHY_BMSR_EXT_STAT 0x0100 +#define PHY_BMSR_PRE_SUP 0x0040 +#define PHY_BMSR_AUTN_COMP 0x0020 +#define PHY_BMSR_RF 0x0010 +#define PHY_BMSR_AUTN_ABLE 0x0008 +#define PHY_BMSR_LS 0x0004 +#define PHY_BMSR_JD 0x0002 +#define PHY_BMSR_EXT 0x0001 + +/*phy ANLPAR */ +#define PHY_ANLPAR_NP 0x8000 +#define PHY_ANLPAR_ACK 0x4000 +#define PHY_ANLPAR_RF 0x2000 +#define PHY_ANLPAR_ASYMP 0x0800 +#define PHY_ANLPAR_PAUSE 0x0400 +#define PHY_ANLPAR_T4 0x0200 +#define PHY_ANLPAR_TXFD 0x0100 +#define PHY_ANLPAR_TX 0x0080 +#define PHY_ANLPAR_10FD 0x0040 +#define PHY_ANLPAR_10 0x0020 +#define PHY_ANLPAR_100 0x0380 /* we can run at 100 */ +/* phy ANLPAR 1000BASE-X */ +#define PHY_X_ANLPAR_NP 0x8000 +#define PHY_X_ANLPAR_ACK 0x4000 +#define PHY_X_ANLPAR_RF_MASK 0x3000 +#define PHY_X_ANLPAR_PAUSE_MASK 0x0180 +#define PHY_X_ANLPAR_HD 0x0040 +#define PHY_X_ANLPAR_FD 0x0020 + +#define PHY_ANLPAR_PSB_MASK 0x001f +#define PHY_ANLPAR_PSB_802_3 0x0001 +#define PHY_ANLPAR_PSB_802_9 0x0002 + +/* phy 1000BTCR */ +#define PHY_1000BTCR_1000FD 0x0200 +#define PHY_1000BTCR_1000HD 0x0100 + +/* phy 1000BTSR */ +#define PHY_1000BTSR_MSCF 0x8000 +#define PHY_1000BTSR_MSCR 0x4000 +#define PHY_1000BTSR_LRS 0x2000 +#define PHY_1000BTSR_RRS 0x1000 +#define PHY_1000BTSR_1000FD 0x0800 +#define PHY_1000BTSR_1000HD 0x0400 + +/* phy EXSR */ +#define PHY_EXSR_1000XF 0x8000 +#define PHY_EXSR_1000XH 0x4000 +#define PHY_EXSR_1000TF 0x2000 +#define PHY_EXSR_1000TH 0x1000 + + + +typedef struct { + VENDOR_DEVICE_PATH EthDevicePath; + EFI_DEVICE_PATH EndDevicePath; +} ETH_DEVICE_PATH; + +// +// Private data for driver. +// +#define ETH_DXE_PRIVATE_DATA_SIGNATURE SIGNATURE_32( 'E', 'T', 'H', 'D' ) + +typedef struct +{ + UINT32 Signature; + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + EFI_SIMPLE_NETWORK_MODE Mode; + ETH_DEVICE_PATH DevicePath; +} ETH_DXE_PRIVATE_DATA; + +#define ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(a) \ + CR( a, ETH_DXE_PRIVATE_DATA, Snp, ETH_DXE_PRIVATE_DATA_SIGNATURE ) + + +EFI_STATUS +EFIAPI +EthStart( + EFI_SIMPLE_NETWORK_PROTOCOL *This +); + +EFI_STATUS +EFIAPI +EthStop( + EFI_SIMPLE_NETWORK_PROTOCOL *This +); + +EFI_STATUS +EFIAPI +EthInitialize( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINTN ExtraRxBufferSize, + UINTN ExtraTxBufferSize +); + +EFI_STATUS +EFIAPI +EthReset( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN ExtendedVerification +); + +EFI_STATUS +EFIAPI +EthShutdown( + EFI_SIMPLE_NETWORK_PROTOCOL *This +); + +EFI_STATUS +EFIAPI +EthReceiveFilters( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINT32 Enable, + UINT32 Disable, + BOOLEAN ResetMCastFilter, + UINTN MCastFilterCnt, + EFI_MAC_ADDRESS *MCastFilter +); + +EFI_STATUS +EFIAPI +EthStationAddress( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN Reset, + EFI_MAC_ADDRESS *New +); + +EFI_STATUS +EFIAPI +EthStatistics( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN Reset, + UINTN *StatisticsSize, + EFI_NETWORK_STATISTICS *StatisticsTable +); + +EFI_STATUS +EFIAPI +EthMCastIpToMac( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN IPv6, + EFI_IP_ADDRESS *IP, + EFI_MAC_ADDRESS *MAC +); + +EFI_STATUS +EFIAPI +EthNvData( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + BOOLEAN ReadWrite, + UINTN Offset, + UINTN BufferSize, + VOID *Buffer +); + +EFI_STATUS +EFIAPI +EthGetStatus( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINT32 *InterruptStatus, + VOID **TxBuf +); + +EFI_STATUS +EFIAPI +EthTransmit( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINTN HeaderSize, + UINTN BufferSize, + VOID *Buffer, + EFI_MAC_ADDRESS *SrcAddr, + EFI_MAC_ADDRESS *DestAddr, + UINT16 *Protocol +); + +EFI_STATUS +EFIAPI +EthReceive( + EFI_SIMPLE_NETWORK_PROTOCOL *This, + UINTN *HeaderSize, + UINTN *BufferSize, + VOID *Buffer, + EFI_MAC_ADDRESS *SrcAddr, + EFI_MAC_ADDRESS *DestAddr, + UINT16 *Protocol +); + +#endif // _Eth_Dxe_H__ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.inf new file mode 100644 index 000000000..e9f649e15 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.inf @@ -0,0 +1,59 @@ +## @file +# +# Component description file for GraphicsConsole module +# +# This is the main routine for initializing the Graphics Console support routines. +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EthDxe + FILE_GUID = 25ac458a-cf60-476e-861a-211c757657a6 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = EthDxeInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = +# COMPONENT_NAME = +# COMPONENT_NAME2 = +# + +[Sources] + EthDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos4210/ExynosPkg.dec + SamsungPlatformPkg/SamsungPlatformPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + MemoryAllocationLib + UefiDriverEntryPoint + IoLib + TimerLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid ## TO_START + +[Guids] + +[Pcd] + gExynosPkgTokenSpaceGuid.PcdSMC911XBase diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390Gic.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390Gic.c new file mode 100644 index 000000000..3224cbef9 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390Gic.c @@ -0,0 +1,70 @@ +/** @file +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include <Uefi.h> +#include <Library/IoLib.h> +#include <Library/ArmGicLib.h> +#include <Library/PcdLib.h> + +UINTN +EFIAPI +ArmGicGetMaxNumInterrupts ( + IN INTN GicDistributorBase + ) +{ + return 32 * ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F) + 1); +} + +VOID +EFIAPI +ArmGicSendSgiTo ( + IN INTN GicDistributorBase, + IN INTN TargetListFilter, + IN INTN CPUTargetList, + IN INTN SgiId + ) +{ + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDSGIR, ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId); +} + +RETURN_STATUS +EFIAPI +ArmGicAcknowledgeInterrupt ( + IN UINTN GicDistributorBase, + IN UINTN GicInterruptInterfaceBase, + OUT UINTN *CoreId, + OUT UINTN *InterruptId + ) +{ + UINT32 Interrupt; + + // Read the Interrupt Acknowledge Register + Interrupt = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIAR); + + // Check if it is a valid interrupt ID + if ((Interrupt & 0x3FF) < ArmGicGetMaxNumInterrupts (GicDistributorBase)) { + // Got a valid SGI number hence signal End of Interrupt by writing to ICCEOIR + MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCEIOR, Interrupt); + + if (CoreId) { + *CoreId = (Interrupt >> 10) & 0x7; + } + if (InterruptId) { + *InterruptId = Interrupt & 0x3FF; + } + return RETURN_SUCCESS; + } else { + return RETURN_INVALID_PARAMETER; + } +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicDxe.c new file mode 100644 index 000000000..4e2fc883d --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicDxe.c @@ -0,0 +1,415 @@ +/*++ + +Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR> +Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR> +Portions copyright (c) 2011-2012, ARM Ltd. All rights reserved.<BR> + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Gic.c + +Abstract: + + Driver implementing the GIC interrupt controller protocol + +--*/ + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Library/ArmGicLib.h> + +#include <Protocol/Cpu.h> +#include <Protocol/HardwareInterrupt.h> + +#define ARM_GIC_DEFAULT_PRIORITY 0x80 + +extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol; + +// +// Notifications +// +EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL; + +// Maximum Number of Interrupts +UINTN mGicNumInterrupts = 0; + +HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL; + +/** + Register Handler for the specified interrupt source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param Handler Callback for interrupt. NULL to unregister + + @retval EFI_SUCCESS Source was updated to support Handler. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +EFI_STATUS +EFIAPI +RegisterInterruptSource ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN HARDWARE_INTERRUPT_HANDLER Handler + ) +{ + if (Source > mGicNumInterrupts) { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) { + return EFI_ALREADY_STARTED; + } + + gRegisteredInterruptHandlers[Source] = Handler; + + // If the interrupt handler is unregistered then disable the interrupt + if (NULL == Handler){ + return This->DisableInterruptSource (This, Source); + } else { + return This->EnableInterruptSource (This, Source); + } +} + +/** + Enable interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt enabled. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +EFI_STATUS +EFIAPI +EnableInterruptSource ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ) +{ + UINT32 RegOffset; + UINTN RegShift; + + if (Source > mGicNumInterrupts) { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + // calculate enable register offset and bit position + RegOffset = Source / 32; + RegShift = Source % 32; + + // write set-enable register + MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISER + (4*RegOffset), 1 << RegShift); + + return EFI_SUCCESS; +} + +/** + Disable interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt disabled. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +EFI_STATUS +EFIAPI +DisableInterruptSource ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ) +{ + UINT32 RegOffset; + UINTN RegShift; + + if (Source > mGicNumInterrupts) { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + // Calculate enable register offset and bit position + RegOffset = Source / 32; + RegShift = Source % 32; + + // Write set-enable register + MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDICER + (4*RegOffset), 1 << RegShift); + + return EFI_SUCCESS; +} + +/** + Return current state of interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param InterruptState TRUE: source enabled, FALSE: source disabled. + + @retval EFI_SUCCESS InterruptState is valid + @retval EFI_DEVICE_ERROR InterruptState is not valid + +**/ +EFI_STATUS +EFIAPI +GetInterruptSourceState ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN BOOLEAN *InterruptState + ) +{ + UINT32 RegOffset; + UINTN RegShift; + + if (Source > mGicNumInterrupts) { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + // calculate enable register offset and bit position + RegOffset = Source / 32; + RegShift = Source % 32; + + if ((MmioRead32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISER + (4*RegOffset)) & (1<<RegShift)) == 0) { + *InterruptState = FALSE; + } else { + *InterruptState = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Signal to the hardware that the End Of Intrrupt state + has been reached. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt EOI'ed. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +EFI_STATUS +EFIAPI +EndOfInterrupt ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ) +{ + if (Source > mGicNumInterrupts) { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCEIOR, Source); + return EFI_SUCCESS; +} + +/** + EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs. + + @param InterruptType Defines the type of interrupt or exception that + occurred on the processor.This parameter is processor architecture specific. + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. + + @return None + +**/ +VOID +EFIAPI +IrqInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINT32 GicInterrupt; + HARDWARE_INTERRUPT_HANDLER InterruptHandler; + + GicInterrupt = MmioRead32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCIAR); + + // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the number of interrupt (ie: Spurious interrupt). + if (GicInterrupt >= mGicNumInterrupts) { + // The special interrupt do not need to be acknowledge + return; + } + + InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt]; + if (InterruptHandler != NULL) { + // Call the registered interrupt handler. + InterruptHandler (GicInterrupt, SystemContext); + } else { + DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt)); + } + + EndOfInterrupt (&gHardwareInterruptProtocol, GicInterrupt); +} + +// +// Making this global saves a few bytes in image size +// +EFI_HANDLE gHardwareInterruptHandle = NULL; + +// +// The protocol instance produced by this driver +// +EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = { + RegisterInterruptSource, + EnableInterruptSource, + DisableInterruptSource, + GetInterruptSourceState, + EndOfInterrupt +}; + +/** + Shutdown our hardware + + DXE Core will disable interrupts and turn off the timer and disable interrupts + after all the event handlers have run. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +ExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Index; + + // Acknowledge all pending interrupts + for (Index = 0; Index < mGicNumInterrupts; Index++) { + DisableInterruptSource (&gHardwareInterruptProtocol, Index); + } + + for (Index = 0; Index < mGicNumInterrupts; Index++) { + EndOfInterrupt (&gHardwareInterruptProtocol, Index); + } + + // Disable Gic Interface + MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x0); + MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0x0); + + // Disable Gic Distributor + MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x0); +} + +/** + Initialize the state information for the CPU Architectural Protocol + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +InterruptDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT32 RegOffset; + UINTN RegShift; + EFI_CPU_ARCH_PROTOCOL *Cpu; + + // Make sure the Interrupt Controller Protocol is not already installed in the system. + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); + + mGicNumInterrupts = ArmGicGetMaxNumInterrupts (PcdGet32(PcdGicDistributorBase)); + + for (Index = 0; Index < mGicNumInterrupts; Index++) { + DisableInterruptSource (&gHardwareInterruptProtocol, Index); + + // Set Priority + RegOffset = Index / 4; + RegShift = (Index % 4) * 8; + MmioAndThenOr32 ( + PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPR + (4*RegOffset), + ~(0xff << RegShift), + ARM_GIC_DEFAULT_PRIORITY << RegShift + ); + } + + // Configure interrupts for cpu 0 + for (Index = 0; Index < (mGicNumInterrupts / 4); Index++) { + MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPTR + (Index*4), 0x01010101); + } + + // Set binary point reg to 0x7 (no preemption) + MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCBPR, 0x7); + + // Set priority mask reg to 0xff to allow all priorities through + MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0xF0); + + // Enable gic cpu interface + MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x1); + + // Enable gic distributor + MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x3); + + // Initialize the array for the Interrupt Handlers + gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &gHardwareInterruptHandle, + &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Get the CPU protocol that this driver requires. + // + Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); + ASSERT_EFI_ERROR(Status); + + // + // Unregister the default exception handler. + // + Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL); + ASSERT_EFI_ERROR(Status); + + // + // Register to receive interrupts + // + Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler); + ASSERT_EFI_ERROR(Status); + + // Register for an ExitBootServicesEvent + Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicDxe.inf new file mode 100644 index 000000000..723931522 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicDxe.inf @@ -0,0 +1,54 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> +# Copyright (c) 2012, ARM Ltd. All rights reserved.<BR> +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PL390GicDxe + FILE_GUID = DE371F7C-DEC4-4D21-ADF1-593ABCC15882 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InterruptDxeInitialize + + +[Sources.common] + PL390Gic.c + PL390GicDxe.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + UefiBootServicesTableLib + DebugLib + PrintLib + MemoryAllocationLib + UefiDriverEntryPoint + IoLib + +[Protocols] + gHardwareInterruptProtocolGuid + gEfiCpuArchProtocolGuid + +[FixedPcd.common] + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + +[Depex] + gEfiCpuArchProtocolGuid diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicLib.inf new file mode 100644 index 000000000..615b41039 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicLib.inf @@ -0,0 +1,28 @@ +#/* @file +# Copyright (c) 2011-2012, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PL390GicLib + FILE_GUID = 03d05ee4-cdeb-458c-9dfc-993f09bdf405 + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmGicLib + +[Sources] + PL390Gic.c + PL390GicNonSec.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicNonSec.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicNonSec.c new file mode 100644 index 000000000..10fcb4e5e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicNonSec.c @@ -0,0 +1,44 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include <Uefi.h> +#include <Library/IoLib.h> +#include <Library/ArmGicLib.h> + + +VOID +EFIAPI +ArmGicEnableInterruptInterface ( + IN INTN GicInterruptInterfaceBase + ) +{ + /* + * Enable the CPU interface in Non-Secure world + * Note: The ICCICR register is banked when Security extensions are implemented + */ + MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR, 0x1); +} + +VOID +EFIAPI +ArmGicEnableDistributor ( + IN INTN GicDistributorBase + ) +{ + /* + * Enable GIC distributor in Non-Secure world. + * Note: The ICDDCR register is banked when Security extensions are implemented + */ + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x1); +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicSec.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicSec.c new file mode 100644 index 000000000..82ecfde6e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicSec.c @@ -0,0 +1,119 @@ +/** @file +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include <Base.h> +#include <Library/ArmLib.h> +#include <Library/DebugLib.h> +#include <Library/ArmPlatformLib.h> +#include <Library/IoLib.h> +#include <Library/ArmGicLib.h> + +/* + * This function configures the all interrupts to be Non-secure. + * + */ +VOID +EFIAPI +ArmGicSetupNonSecure ( + IN UINTN MpId, + IN INTN GicDistributorBase, + IN INTN GicInterruptInterfaceBase + ) +{ + UINTN InterruptId; + UINTN CachedPriorityMask; + UINTN Index; + + CachedPriorityMask = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR); + + // Set priority Mask so that no interrupts get through to CPU + MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0); + + // Check if there are any pending interrupts + //TODO: could be extended to take Peripheral interrupts into consideration, but at the moment only SGI's are taken into consideration. + while(0 != (MmioRead32 (GicDistributorBase + ARM_GIC_ICDICPR) & 0xF)) { + // Some of the SGI's are still pending, read Ack register and send End of Interrupt Signal + InterruptId = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIAR); + + // Write to End of interrupt signal + MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCEIOR, InterruptId); + } + + // Only the primary core should set the Non Secure bit to the SPIs (Shared Peripheral Interrupt). + if (ArmPlatformIsPrimaryCore (MpId)) { + // Ensure all GIC interrupts are Non-Secure + for (Index = 0; Index < (ArmGicGetMaxNumInterrupts (GicDistributorBase) / 32); Index++) { + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4), 0xffffffff); + } + } else { + // The secondary cores only set the Non Secure bit to their banked PPIs + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR, 0xffffffff); + } + + // Ensure all interrupts can get through the priority mask + MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, CachedPriorityMask); +} + +/* + * This function configures the interrupts set by the mask to be secure. + * + */ +VOID +EFIAPI +ArmGicSetSecureInterrupts ( + IN UINTN GicDistributorBase, + IN UINTN* GicSecureInterruptMask, + IN UINTN GicSecureInterruptMaskSize + ) +{ + UINTN Index; + UINT32 InterruptStatus; + + // We must not have more interrupts defined by the mask than the number of available interrupts + ASSERT(GicSecureInterruptMaskSize <= (ArmGicGetMaxNumInterrupts (GicDistributorBase) / 32)); + + // Set all the interrupts defined by the mask as Secure + for (Index = 0; Index < GicSecureInterruptMaskSize; Index++) { + InterruptStatus = MmioRead32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4)); + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4), InterruptStatus & (~GicSecureInterruptMask[Index])); + } +} + +VOID +EFIAPI +ArmGicEnableInterruptInterface ( + IN INTN GicInterruptInterfaceBase + ) +{ + // Set Priority Mask to allow interrupts + MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0x000000F0); + + // Enable CPU interface in Secure world + // Enable CPU inteface in Non-secure World + // Signal Secure Interrupts to CPU using FIQ line * + MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR, + ARM_GIC_ICCICR_ENABLE_SECURE | + ARM_GIC_ICCICR_ENABLE_NS | + ARM_GIC_ICCICR_SIGNAL_SECURE_TO_FIQ); +} + +VOID +EFIAPI +ArmGicEnableDistributor ( + IN INTN GicDistributorBase + ) +{ + // Turn on the GIC distributor + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 1); +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicSecLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicSecLib.inf new file mode 100644 index 000000000..ab399b4fb --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gic400Dxe/PL390GicSecLib.inf @@ -0,0 +1,37 @@ +#/* @file +# Copyright (c) 2011-2012, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PL390GicSecLib + FILE_GUID = 85f3cf80-b5f4-11df-9855-0002a5d5c51b + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmGicLib + +[Sources] + PL390Gic.c + PL390GicSec.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + ArmLib + DebugLib + IoLib + PcdLib + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gpio/Gpio.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gpio/Gpio.c new file mode 100644 index 000000000..cdd4102e5 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gpio/Gpio.c @@ -0,0 +1,177 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Uefi.h> + +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/ExynosGpio.h> +#include <Platform/ArmPlatform.h> +#include <Library/ExynosLib.h> + + + +EFI_STATUS +Get ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + OUT UINTN *Value + ) +{ + UINTN Port; + UINTN Pin; + UINT32 DataInRegister; + + if (Value == NULL) + { + return EFI_UNSUPPORTED; + } + + Port = GPIO_PORT(Gpio); + Pin = GPIO_PIN(Gpio); + + DataInRegister = GpioBase(Port) + GPIO_DATAIN; + + if (MmioRead32 (DataInRegister) & GPIO_DATAIN_MASK(Pin)) { + *Value = 1; + } else { + *Value = 0; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +Set ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + IN EXYNOS_GPIO_MODE Mode + ) +{ + UINTN Port; + UINTN Pin; + UINT32 OutputRegister; + + Port = GPIO_PORT(Gpio); + Pin = GPIO_PIN(Gpio); + OutputRegister = GpioBase(Port) + GPIO_CON; + DEBUG ((EFI_D_INFO, "Gpio->Set: Gpio(0x%x), Port (0x%x), Pin (0x%x), Register (0x%x).\n", Gpio, Port, Pin, OutputRegister)); + switch (Mode) + { + case GPIO_MODE_INPUT: + break; + case GPIO_MODE_OUTPUT_0: + MmioAndThenOr32(OutputRegister, ~GPIO_SFN_MASK(Pin), GPIO_OP_EN(Pin)); + MmioAndThenOr32((GpioBase(Port) + GPIO_DATAIN), ~GPIO_DATAIN_MASK(Pin), GPIO_DATA_LOW(Pin)); + break; + case GPIO_MODE_OUTPUT_1: + MmioAndThenOr32(OutputRegister, ~GPIO_SFN_MASK(Pin), GPIO_OP_EN(Pin)); + MmioAndThenOr32((GpioBase(Port) + GPIO_DATAIN), ~GPIO_DATAIN_MASK(Pin), GPIO_DATA_HIGH(Pin)); + break; + case GPIO_MODE_SPECIAL_FUNCTION_2: + MmioAndThenOr32(OutputRegister, ~GPIO_SFN_MASK(Pin), GPIO_SFN_EN(Pin)); + break; + default: + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetMode ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + OUT EXYNOS_GPIO_MODE *Mode + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +SetPull ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + IN EXYNOS_GPIO_PULL Direction + ) +{ + UINTN Port; + UINTN Pin; + UINT32 OutputRegister; + + Port = GPIO_PORT(Gpio); + Pin = GPIO_PIN(Gpio); + OutputRegister = GpioBase(Port) + GPIO_PUD; + DEBUG ((EFI_D_INFO, "Gpio->SetPull: Gpio(0x%x), Port (0x%x), Pin (0x%x), Register (0x%x).\n", Gpio, Port, Pin, OutputRegister)); + switch (Direction) + { + case GPIO_PULL_NONE: + MmioAndThenOr32(OutputRegister, ~GPIO_PUD_MASK(Pin), GPIO_PUD_DIS(Pin)); + break; + case GPIO_PULL_UP: + MmioAndThenOr32(OutputRegister, ~GPIO_PUD_MASK(Pin), GPIO_PUP_EN(Pin)); + break; + case GPIO_PULL_DOWN: + MmioAndThenOr32(OutputRegister, ~GPIO_PUD_MASK(Pin), GPIO_PDN_EN(Pin)); + break; + default: + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + + +EFI_STATUS +SetStrength ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + IN EXYNOS_GPIO_STRN Strength + ) +{ + UINTN Port; + UINTN Pin; + UINT32 OutputRegister; + + Port = GPIO_PORT(Gpio); + Pin = GPIO_PIN(Gpio); + OutputRegister = GpioBase(Port) + GPIO_DRV; + MmioAndThenOr32(OutputRegister, ~GPIO_DRV_MASK(Pin), GPIO_DRV_SET(Strength,Pin)); + + return EFI_SUCCESS; +} + + + +EXYNOS_GPIO Gpio = { + Get, + Set, + GetMode, + SetPull, + SetStrength +}; + +EFI_STATUS +GpioInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->InstallMultipleProtocolInterfaces(&ImageHandle, &gSamsungPlatformGpioProtocolGuid, &Gpio, NULL); + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gpio/Gpio.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gpio/Gpio.inf new file mode 100644 index 000000000..605b80576 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/Gpio/Gpio.inf @@ -0,0 +1,46 @@ +#/** @file +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Gpio + FILE_GUID = E7D9CAE1-6930-46E3-BDF9-0027446E7DF2 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = GpioInitialize + + +[Sources.common] + Gpio.c + +[Packages] + MdePkg/MdePkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + SamsungPlatformPkg/SamsungPlatformPkg.dec + +[LibraryClasses] + IoLib + UefiDriverEntryPoint + ExynosLib + DebugLib + +[Guids] + +[Protocols] + gSamsungPlatformGpioProtocolGuid + +[Pcd] + +[depex] + TRUE diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.c new file mode 100644 index 000000000..75ffc2668 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.c @@ -0,0 +1,241 @@ +#include <Library/PcdLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/ArmGicLib.h> +#include <Library/UncachedMemoryAllocationLib.h> + +#include <Protocol/Hash.h> + +#include <Platform/ArmPlatform.h> +#include <Platform/Exynos5250.h> + +#include "HashDxe.h" + +#define CLOCK_ON 1 +#define CLOCK_OFF 0 + +EFI_STATUS +EFIAPI +CryptoClockGating ( + IN UINT32 clock_status + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 CmuBase; + UINT32 value; + + CmuBase = PcdGet32(PcdCmuBase); + value = MmioRead32(CmuBase + SSS_CMU_OFFSET); + + if (clock_status == CLOCK_ON) + MmioWrite32(CmuBase + SSS_CMU_OFFSET, value | CLK_SSS); + else if (clock_status == CLOCK_OFF) + MmioWrite32(CmuBase + SSS_CMU_OFFSET, value & ~CLK_SSS); + else { + DEBUG((EFI_D_ERROR, "[HashDxe] : Unsupported SSS clock status\n")); + Status = EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + Returns the size of the hash which results from a specific algorithm. + + @param[in] This Points to this instance of EFI_HASH_PROTOCOL. + @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use. + @param[out] HashSize Holds the returned size of the algorithm's hash. + + @retval EFI_SUCCESS Hash size returned successfully. + @retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported + by this driver. + +**/ +EFI_STATUS +EFIAPI +HashDxeGetHashSize ( + IN CONST EFI_HASH_PROTOCOL *This, + IN CONST EFI_GUID *HashAlgorithm, + OUT UINTN *HashSize + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha1Guid)) + *HashSize = sizeof(EFI_SHA1_HASH); + else if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha256Guid)) + *HashSize = sizeof(EFI_SHA256_HASH); + else { + DEBUG((EFI_D_ERROR, "[HashDxe] : Unsupported Hash Algorithm\n")); + Status = EFI_UNSUPPORTED; + } + + return Status; +} + +/** + Returns the size of the hash which results from a specific algorithm. + + @param[in] This Points to this instance of EFI_HASH_PROTOCOL. + @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use. + @param[in] Extend Specifies whether to create a new hash (FALSE) or extend the specified + existing hash (TRUE). + @param[in] Message Points to the start of the message. + @param[in] MessageSize The size of Message, in bytes. + @param[in,out] Hash On input, if Extend is TRUE, then this holds the hash to extend. On + output, holds the resulting hash computed from the message. + + @retval EFI_SUCCESS Hash returned successfully. + @retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported by this + driver. Or, Extend is TRUE, and the algorithm doesn't support extending the hash. + +**/ +EFI_STATUS +EFIAPI +HashDxeRunHash ( + IN CONST EFI_HASH_PROTOCOL *This, + IN CONST EFI_GUID *HashAlgorithm, + IN BOOLEAN Extend, + IN CONST UINT8 *Message, + IN UINT64 MessageSize, + IN OUT EFI_HASH_OUTPUT *Hash + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 value; + UINT32 CryptoBase; + UINT32 TotalMessageSize; + UINT32 HashResult[8]; + UINT8 *TempMessage; + + CryptoBase = PcdGet32(PcdCryptoBase); + + CryptoClockGating(CLOCK_ON); + + /* Flush HRDMA */ + MmioWrite32(CryptoBase + SSS_FC_HRDMAC, SSS_FC_HRDMACFLUSH_ON); + MmioWrite32(CryptoBase + SSS_FC_HRDMAC, SSS_FC_HRDMACFLUSH_OFF); + + /* Set byte swap of in/out data and iv */ + MmioWrite32(CryptoBase + SSS_HASH_BYTESWAP, + SSS_HASH_SWAPDI_ON | SSS_HASH_SWAPDO_ON | SSS_HASH_SWAPIV_ON); + + /* Select HASH input mux as external source */ + value = MmioRead32(CryptoBase + SSS_FC_FIFOCTRL); + value = (value & ~SSS_FC_SELHASH_MASK) | SSS_FC_SELHASH_EXOUT; + MmioWrite32(CryptoBase + SSS_FC_FIFOCTRL, value); + + /* Set HASH algorithm and start hash engine */ + if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha1Guid)) + value = SSS_HASH_ENGSEL_SHA1HASH | SSS_HASH_STARTBIT_ON; + else if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha256Guid)) + value = SSS_HASH_ENGSEL_SHA256HASH | SSS_HASH_STARTBIT_ON; + else { + DEBUG((EFI_D_ERROR, "[HashDxe] : Unsupported Hash Algorithm\n")); + Status = EFI_UNSUPPORTED; + return Status; + } + MmioWrite32(CryptoBase + SSS_HASH_CONTROL, value); + + /* Enable FIFO mode */ + MmioWrite32(CryptoBase + SSS_HASH_FIFO_MODE, SSS_HASH_FIFO_ON); + + if (Extend == 0) + TotalMessageSize = MessageSize; + else if (Extend == 1) { + if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha1Guid)) { + TempMessage = (UINT8 *)UncachedAllocatePool(sizeof(EFI_SHA1_HASH) + MessageSize); + CopyMem(TempMessage, Hash, sizeof(EFI_SHA1_HASH)); + CopyMem(TempMessage + sizeof(EFI_SHA1_HASH), Message, MessageSize); + TotalMessageSize = sizeof(EFI_SHA1_HASH) + MessageSize; + } else if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha256Guid)) { + TempMessage = (UINT8 *)UncachedAllocatePool(sizeof(EFI_SHA256_HASH) + MessageSize); + CopyMem(TempMessage, Hash, sizeof(EFI_SHA256_HASH)); + CopyMem(TempMessage + sizeof(EFI_SHA256_HASH), Message, MessageSize); + TotalMessageSize = sizeof(EFI_SHA256_HASH) + MessageSize; + } + } + + MmioWrite32(CryptoBase + SSS_HASH_MSGSIZE_LOW, TotalMessageSize); + MmioWrite32(CryptoBase + SSS_HASH_MSGSIZE_HIGH, 0); + + /* Set HRDMA */ + /* + * Message must be a physical address. Check it. + */ + if (Extend == 0) + MmioWrite32(CryptoBase + SSS_FC_HRDMAS, (UINT32)Message); + else if (Extend == 1) + MmioWrite32(CryptoBase + SSS_FC_HRDMAS, (UINT32)TempMessage); + + MmioWrite32(CryptoBase + SSS_FC_HRDMAL, TotalMessageSize); + + /* Check the HASH status */ + while ((MmioRead32(CryptoBase + SSS_HASH_STATUS) & SSS_HASH_MSGDONE_MASK) + == SSS_HASH_MSGDONE_OFF); + + /* Clear MSG_DONE bit */ + MmioWrite32(CryptoBase + SSS_HASH_STATUS, SSS_HASH_MSGDONE_ON); + + /* Read hash result */ + HashResult[0] = MmioRead32(CryptoBase + SSS_HASH_RESULT1); + HashResult[1] = MmioRead32(CryptoBase + SSS_HASH_RESULT2); + HashResult[2] = MmioRead32(CryptoBase + SSS_HASH_RESULT3); + HashResult[3] = MmioRead32(CryptoBase + SSS_HASH_RESULT4); + HashResult[4] = MmioRead32(CryptoBase + SSS_HASH_RESULT5); + + if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha256Guid)) { + HashResult[5] = MmioRead32(CryptoBase + SSS_HASH_RESULT6); + HashResult[6] = MmioRead32(CryptoBase + SSS_HASH_RESULT7); + HashResult[7] = MmioRead32(CryptoBase + SSS_HASH_RESULT8); + } + + if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha1Guid)) + CopyMem(Hash, HashResult, sizeof(EFI_SHA1_HASH)); + else if (CompareGuid(HashAlgorithm, &gEfiHashAlgorithmSha256Guid)) + CopyMem(Hash, HashResult, sizeof(EFI_SHA256_HASH)); + else { + DEBUG((EFI_D_ERROR, "[HashDxe] : Unsupported Hash Algorithm\n")); + Status = EFI_UNSUPPORTED; + return Status; + } + + MmioWrite32(CryptoBase + SSS_FC_INTPEND, SSS_FC_HRDMA); + + return Status; +} + +EFI_HASH_PROTOCOL gHash = { + HashDxeGetHashSize, + HashDxeRunHash +}; + +/** + Initialize the state information for the HashDxe + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +HashDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + Status = gBS->InstallMultipleProtocolInterfaces( + &ImageHandle, + &gEfiHashProtocolGuid, + &gHash, + NULL + ); + + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.h new file mode 100644 index 000000000..6a2562916 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.h @@ -0,0 +1,417 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CRYPTODXE_H_ +#define _CRYPTODXE_H_ + +#include <Uefi.h> + +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseMemoryLib.h> +#include <Protocol/BlockIo.h> +#include <Protocol/DevicePath.h> + +#define SSS_CMU_OFFSET (0x8800) +#define CLK_SSS (1 << 2) + +#define SSS_FC_OFFSET (0x0) +#define SSS_AES_OFFSET (0x200) +#define SSS_HASH_OFFSET (0x400) + +/* Feed control registers */ +#define SSS_FC_INTSTAT (SSS_FC_OFFSET + 0x00) +#define SSS_FC_INTENSET (SSS_FC_OFFSET + 0x04) +#define SSS_FC_INTENCLR (SSS_FC_OFFSET + 0x08) +#define SSS_FC_INTPEND (SSS_FC_OFFSET + 0x0C) +#define SSS_FC_FIFOSTAT (SSS_FC_OFFSET + 0x10) +#define SSS_FC_FIFOCTRL (SSS_FC_OFFSET + 0x14) +#define SSS_FC_GLOBAL (SSS_FC_OFFSET + 0x18) +#define SSS_FC_BRDMAS (SSS_FC_OFFSET + 0x20) +#define SSS_FC_BRDMAL (SSS_FC_OFFSET + 0x24) +#define SSS_FC_BRDMAC (SSS_FC_OFFSET + 0x28) +#define SSS_FC_BTDMAS (SSS_FC_OFFSET + 0x30) +#define SSS_FC_BTDMAL (SSS_FC_OFFSET + 0x34) +#define SSS_FC_BTDMAC (SSS_FC_OFFSET + 0x38) +#define SSS_FC_HRDMAS (SSS_FC_OFFSET + 0x40) +#define SSS_FC_HRDMAL (SSS_FC_OFFSET + 0x44) +#define SSS_FC_HRDMAC (SSS_FC_OFFSET + 0x48) +#define SSS_FC_PKDMAS (SSS_FC_OFFSET + 0x50) +#define SSS_FC_PKDMAL (SSS_FC_OFFSET + 0x54) +#define SSS_FC_PKDMAC (SSS_FC_OFFSET + 0x58) +#define SSS_FC_PKDMAO (SSS_FC_OFFSET + 0x5C) + +/* AES control registers */ +#define SSS_AES_CONTROL (SSS_AES_OFFSET + 0x00) +#define SSS_AES_STATUS (SSS_AES_OFFSET + 0x04) + +#define SSS_AES_IN1 (SSS_AES_OFFSET + 0x10) +#define SSS_AES_IN2 (SSS_AES_OFFSET + 0x14) +#define SSS_AES_IN3 (SSS_AES_OFFSET + 0x18) +#define SSS_AES_IN4 (SSS_AES_OFFSET + 0x1C) + +#define SSS_AES_OUT1 (SSS_AES_OFFSET + 0x20) +#define SSS_AES_OUT2 (SSS_AES_OFFSET + 0x24) +#define SSS_AES_OUT3 (SSS_AES_OFFSET + 0x28) +#define SSS_AES_OUT4 (SSS_AES_OFFSET + 0x2C) + +#define SSS_AES_IV1 (SSS_AES_OFFSET + 0x30) +#define SSS_AES_IV2 (SSS_AES_OFFSET + 0x34) +#define SSS_AES_IV3 (SSS_AES_OFFSET + 0x38) +#define SSS_AES_IV4 (SSS_AES_OFFSET + 0x3C) + +#define SSS_AES_CNT1 (SSS_AES_OFFSET + 0x40) +#define SSS_AES_CNT2 (SSS_AES_OFFSET + 0x44) +#define SSS_AES_CNT3 (SSS_AES_OFFSET + 0x48) +#define SSS_AES_CNT4 (SSS_AES_OFFSET + 0x4C) + +#define SSS_AES_KEY1 (SSS_AES_OFFSET + 0x80) +#define SSS_AES_KEY2 (SSS_AES_OFFSET + 0x84) +#define SSS_AES_KEY3 (SSS_AES_OFFSET + 0x88) +#define SSS_AES_KEY4 (SSS_AES_OFFSET + 0x8C) +#define SSS_AES_KEY5 (SSS_AES_OFFSET + 0x90) +#define SSS_AES_KEY6 (SSS_AES_OFFSET + 0x94) +#define SSS_AES_KEY7 (SSS_AES_OFFSET + 0x98) +#define SSS_AES_KEY8 (SSS_AES_OFFSET + 0x9C) + +/* TDES control registers */ +#define SSS_TDES_CONTROL (SSS_TDES_OFFSET + 0x00) +#define SSS_TDES_STATUS (SSS_TDES_OFFSET + 0x04) + +#define SSS_TDES_KEY11 (SSS_TDES_OFFSET + 0x10) +#define SSS_TDES_KEY12 (SSS_TDES_OFFSET + 0x14) +#define SSS_TDES_KEY21 (SSS_TDES_OFFSET + 0x18) +#define SSS_TDES_KEY22 (SSS_TDES_OFFSET + 0x1C) +#define SSS_TDES_KEY31 (SSS_TDES_OFFSET + 0x20) +#define SSS_TDES_KEY32 (SSS_TDES_OFFSET + 0x24) + +#define SSS_TDES_IV1 (SSS_TDES_OFFSET + 0x28) +#define SSS_TDES_IV2 (SSS_TDES_OFFSET + 0x2C) + +#define SSS_TDES_IN1 (SSS_TDES_OFFSET + 0x30) +#define SSS_TDES_IN2 (SSS_TDES_OFFSET + 0x34) + +#define SSS_TDES_OUT1 (SSS_TDES_OFFSET + 0x38) +#define SSS_TDES_OUT2 (SSS_TDES_OFFSET + 0x3C) + +/* HASH control registers */ +#define SSS_HASH_CONTROL (SSS_HASH_OFFSET + 0x00) +#define SSS_HASH_CONTROL2 (SSS_HASH_OFFSET + 0x04) +#define SSS_HASH_FIFO_MODE (SSS_HASH_OFFSET + 0x08) +#define SSS_HASH_BYTESWAP (SSS_HASH_OFFSET + 0x0C) +#define SSS_HASH_STATUS (SSS_HASH_OFFSET + 0x10) +#define SSS_HASH_MSGSIZE_LOW (SSS_HASH_OFFSET + 0x20) +#define SSS_HASH_MSGSIZE_HIGH (SSS_HASH_OFFSET + 0x24) +#define SSS_HASH_PRELEN_LOW (SSS_HASH_OFFSET + 0x28) +#define SSS_HASH_PRELEN_HIGH (SSS_HASH_OFFSET + 0x2C) + +#define SSS_HASH_IN1 (SSS_HASH_OFFSET + 0x30) +#define SSS_HASH_IN2 (SSS_HASH_OFFSET + 0x34) +#define SSS_HASH_IN3 (SSS_HASH_OFFSET + 0x38) +#define SSS_HASH_IN4 (SSS_HASH_OFFSET + 0x3C) +#define SSS_HASH_IN5 (SSS_HASH_OFFSET + 0x40) +#define SSS_HASH_IN6 (SSS_HASH_OFFSET + 0x44) +#define SSS_HASH_IN7 (SSS_HASH_OFFSET + 0x48) +#define SSS_HASH_IN8 (SSS_HASH_OFFSET + 0x4C) +#define SSS_HASH_IN9 (SSS_HASH_OFFSET + 0x50) +#define SSS_HASH_IN10 (SSS_HASH_OFFSET + 0x54) +#define SSS_HASH_IN11 (SSS_HASH_OFFSET + 0x58) +#define SSS_HASH_IN12 (SSS_HASH_OFFSET + 0x5C) +#define SSS_HASH_IN13 (SSS_HASH_OFFSET + 0x60) +#define SSS_HASH_IN14 (SSS_HASH_OFFSET + 0x64) +#define SSS_HASH_IN15 (SSS_HASH_OFFSET + 0x68) +#define SSS_HASH_IN16 (SSS_HASH_OFFSET + 0x6C) + +#define SSS_HASH_HMAC_KEY_IN1 (SSS_HASH_OFFSET + 0x70) +#define SSS_HASH_HMAC_KEY_IN2 (SSS_HASH_OFFSET + 0x74) +#define SSS_HASH_HMAC_KEY_IN3 (SSS_HASH_OFFSET + 0x78) +#define SSS_HASH_HMAC_KEY_IN4 (SSS_HASH_OFFSET + 0x7C) +#define SSS_HASH_HMAC_KEY_IN5 (SSS_HASH_OFFSET + 0x80) +#define SSS_HASH_HMAC_KEY_IN6 (SSS_HASH_OFFSET + 0x84) +#define SSS_HASH_HMAC_KEY_IN7 (SSS_HASH_OFFSET + 0x88) +#define SSS_HASH_HMAC_KEY_IN8 (SSS_HASH_OFFSET + 0x8C) +#define SSS_HASH_HMAC_KEY_IN9 (SSS_HASH_OFFSET + 0x90) +#define SSS_HASH_HMAC_KEY_IN10 (SSS_HASH_OFFSET + 0x94) +#define SSS_HASH_HMAC_KEY_IN11 (SSS_HASH_OFFSET + 0x98) +#define SSS_HASH_HMAC_KEY_IN12 (SSS_HASH_OFFSET + 0x9C) +#define SSS_HASH_HMAC_KEY_IN13 (SSS_HASH_OFFSET + 0xA0) +#define SSS_HASH_HMAC_KEY_IN14 (SSS_HASH_OFFSET + 0xA4) +#define SSS_HASH_HMAC_KEY_IN15 (SSS_HASH_OFFSET + 0xA8) +#define SSS_HASH_HMAC_KEY_IN16 (SSS_HASH_OFFSET + 0xAC) + +#define SSS_HASH_IV1 (SSS_HASH_OFFSET + 0xB0) +#define SSS_HASH_IV2 (SSS_HASH_OFFSET + 0xB4) +#define SSS_HASH_IV3 (SSS_HASH_OFFSET + 0xB8) +#define SSS_HASH_IV4 (SSS_HASH_OFFSET + 0xBC) +#define SSS_HASH_IV5 (SSS_HASH_OFFSET + 0xC0) +#define SSS_HASH_IV6 (SSS_HASH_OFFSET + 0xC4) +#define SSS_HASH_IV7 (SSS_HASH_OFFSET + 0xC8) +#define SSS_HASH_IV8 (SSS_HASH_OFFSET + 0xCC) + +#define SSS_HASH_RESULT1 (SSS_HASH_OFFSET + 0x100) +#define SSS_HASH_RESULT2 (SSS_HASH_OFFSET + 0x104) +#define SSS_HASH_RESULT3 (SSS_HASH_OFFSET + 0x108) +#define SSS_HASH_RESULT4 (SSS_HASH_OFFSET + 0x10C) +#define SSS_HASH_RESULT5 (SSS_HASH_OFFSET + 0x110) +#define SSS_HASH_RESULT6 (SSS_HASH_OFFSET + 0x114) +#define SSS_HASH_RESULT7 (SSS_HASH_OFFSET + 0x118) +#define SSS_HASH_RESULT8 (SSS_HASH_OFFSET + 0x11C) + +#define SSS_HASH_SEED1 (SSS_HASH_OFFSET + 0x140) +#define SSS_HASH_SEED2 (SSS_HASH_OFFSET + 0x144) +#define SSS_HASH_SEED3 (SSS_HASH_OFFSET + 0x148) +#define SSS_HASH_SEED4 (SSS_HASH_OFFSET + 0x14C) +#define SSS_HASH_SEED5 (SSS_HASH_OFFSET + 0x150) + +#define SSS_HASH_PRNG1 (SSS_HASH_OFFSET + 0x160) +#define SSS_HASH_PRNG2 (SSS_HASH_OFFSET + 0x164) +#define SSS_HASH_PRNG3 (SSS_HASH_OFFSET + 0x168) +#define SSS_HASH_PRNG4 (SSS_HASH_OFFSET + 0x16C) +#define SSS_HASH_PRNG5 (SSS_HASH_OFFSET + 0x170) + +/* PKA control registers */ +#define SSS_PKA_SFR0 (SSS_PKA_OFFSET + 0x00) +#define SSS_PKA_SFR1 (SSS_PKA_OFFSET + 0x04) +#define SSS_PKA_SFR2 (SSS_PKA_OFFSET + 0x08) +#define SSS_PKA_SFR3 (SSS_PKA_OFFSET + 0x0C) +#define SSS_PKA_SFR4 (SSS_PKA_OFFSET + 0x10) + + +/***************************************************************** + OFFSET +*****************************************************************/ + +/* SSS_FC_INT */ +#define SSS_FC_PKDMA (1 << 0) +#define SSS_FC_HRDMA (1 << 1) +#define SSS_FC_BTDMA (1 << 2) +#define SSS_FC_BRDMA (1 << 3) +#define SSS_FC_PRNG_ERROR (1 << 4) +#define SSS_FC_MSG_DONE (1 << 5) +#define SSS_FC_PRNG_DONE (1 << 6) +#define SSS_FC_PARTIAL_DONE (1 << 7) + +/* SSS_FC_FIFOSTAT */ +#define SSS_FC_PKFIFO_EMPTY (1 << 0) +#define SSS_FC_PKFIFO_FULL (1 << 1) +#define SSS_FC_HRFIFO_EMPTY (1 << 2) +#define SSS_FC_HRFIFO_FULL (1 << 3) +#define SSS_FC_BTFIFO_EMPTY (1 << 4) +#define SSS_FC_BTFIFO_FULL (1 << 5) +#define SSS_FC_BRFIFO_EMPTY (1 << 6) +#define SSS_FC_BRFIFO_FULL (1 << 7) + +/* SSS_FC_FIFOCTRL */ +#define SSS_FC_SELHASH_MASK (3 << 0) +#define SSS_FC_SELHASH_EXOUT (0 << 0) +#define SSS_FC_SELHASH_BCIN (1 << 0) +#define SSS_FC_SELHASH_BCOUT (2 << 0) +#define SSS_FC_SELBC_MASK (1 << 2) +#define SSS_FC_SELBC_AES (0 << 2) +#define SSS_FC_SELBC_DES (1 << 2) + +/* SSS_FC_GLOBAL */ +#define SSS_FC_SSS_RESET (1 << 0) +#define SSS_FC_DMA_RESET (1 << 1) +#define SSS_FC_AES_RESET (1 << 2) +#define SSS_FC_DES_RESET (1 << 3) +#define SSS_FC_HASH_RESET (1 << 4) +#define SSS_FC_AXI_ENDIAN_MASK (3 << 6) +#define SSS_FC_AXI_ENDIAN_LE (0 << 6) +#define SSS_FC_AXI_ENDIAN_BIBE (1 << 6) +#define SSS_FC_AXI_ENDIAN_WIBE (2 << 6) + +/* Feed control - BRDMA control */ +#define SSS_FC_BRDMACFLUSH_OFF (0 << 0) +#define SSS_FC_BRDMACFLUSH_ON (1 << 0) +#define SSS_FC_BRDMACSWAP_ON (1 << 1) +#define SSS_FC_BRDMACARPROT_MASK (0x7 << 2) +#define SSS_FC_BRDMACARPROT_OFS (2) +#define SSS_FC_BRDMACARCACHE_MASK (0xF << 5) +#define SSS_FC_BRDMACARCACHE_OFS (5) + +/* Feed control - BTDMA control */ +#define SSS_FC_BTDMACFLUSH_OFF (0 << 0) +#define SSS_FC_BTDMACFLUSH_ON (1 << 0) +#define SSS_FC_BTDMACSWAP_ON (1 << 1) +#define SSS_FC_BTDMACAWPROT_MASK (0x7 << 2) +#define SSS_FC_BTDMACAWPROT_OFS (2) +#define SSS_FC_BTDMACAWCACHE_MASK (0xF << 5) +#define SSS_FC_BTDMACAWCACHE_OFS (5) + +/* Feed control - HRDMA control */ +#define SSS_FC_HRDMACFLUSH_OFF (0 << 0) +#define SSS_FC_HRDMACFLUSH_ON (1 << 0) +#define SSS_FC_HRDMACSWAP_ON (1 << 1) + +/* Feed control - PKDMA control */ +#define SSS_FC_PKDMACBYTESWAP_ON (1 << 3) +#define SSS_FC_PKDMACDESEND_ON (1 << 2) +#define SSS_FC_PKDMACTRANSMIT_ON (1 << 1) +#define SSS_FC_PKDMACFLUSH_ON (1 << 0) + +/* Feed control - PKDMA offset */ +#define SSS_FC_SRAMOFFSET_MASK (0xFFF) + +/* AES control */ +#define SSS_AES_MODE_MASK (1 << 0) +#define SSS_AES_MODE_ENC (0 << 0) +#define SSS_AES_MODE_DEC (1 << 0) +#define SSS_AES_OPERMODE_MASK (3 << 1) +#define SSS_AES_OPERMODE_ECB (0 << 1) +#define SSS_AES_OPERMODE_CBC (1 << 1) +#define SSS_AES_OPERMODE_CTR (2 << 1) +/* +TODO +CTS MODE define +*/ +#define SSS_AES_OPERMODE_CTS (3 << 1) + +#define SSS_AES_FIFO_MASK (1 << 3) +#define SSS_AES_FIFO_OFF (0 << 3) +#define SSS_AES_FIFO_ON (1 << 3) +#define SSS_AES_KEYSIZE_MASK (3 << 4) +#define SSS_AES_KEYSIZE_128 (0 << 4) +#define SSS_AES_KEYSIZE_192 (1 << 4) +#define SSS_AES_KEYSIZE_256 (2 << 4) +#define SSS_AES_KEYCNGMODE_MASK (1 << 6) +#define SSS_AES_KEYCNGMODE_OFF (0 << 6) +#define SSS_AES_KEYCNGMODE_ON (1 << 6) +#define SSS_AES_SWAP_MASK (0x1F << 7) +#define SSS_AES_SWAPKEY_OFF (0 << 7) +#define SSS_AES_SWAPKEY_ON (1 << 7) +#define SSS_AES_SWAPCNT_OFF (0 << 8) +#define SSS_AES_SWAPCNT_ON (1 << 8) +#define SSS_AES_SWAPIV_OFF (0 << 9) +#define SSS_AES_SWAPIV_ON (1 << 9) +#define SSS_AES_SWAPDO_OFF (0 << 10) +#define SSS_AES_SWAPDO_ON (1 << 10) +#define SSS_AES_SWAPDI_OFF (0 << 11) +#define SSS_AES_SWAPDI_ON (1 << 11) +#define SSS_AES_COUNTERSIZE_MASK (3 << 12) +#define SSS_AES_COUNTERSIZE_128 (0 << 12) +#define SSS_AES_COUNTERSIZE_64 (1 << 12) +#define SSS_AES_COUNTERSIZE_32 (2 << 12) +#define SSS_AES_COUNTERSIZE_16 (3 << 12) + +/* AES status */ +#define SSS_AES_OUTRDY_MASK (1 << 0) +#define SSS_AES_OUTRDY_OFF (0 << 0) +#define SSS_AES_OUTRDY_ON (1 << 0) +#define SSS_AES_INRDY_MASK (1 << 1) +#define SSS_AES_INRDY_OFF (0 << 1) +#define SSS_AES_INRDY_ON (1 << 1) +#define SSS_AES_BUSY_MASK (1 << 2) +#define SSS_AES_BUSY_OFF (0 << 2) +#define SSS_AES_BUSY_ON (1 << 2) + +/* TDES control */ +#define SSS_TDES_MODE_MASK (1 << 0) +#define SSS_TDES_MODE_ENC (0 << 0) +#define SSS_TDES_MODE_DEC (1 << 0) +#define SSS_TDES_OPERMODE_MASK (1 << 1) +#define SSS_TDES_OPERMODE_ECB (0 << 1) +#define SSS_TDES_OPERMODE_CBC (1 << 1) +#define SSS_TDES_SEL_MASK (3 << 3) +#define SSS_TDES_SEL_DES (0 << 3) +#define SSS_TDES_SEL_TDESEDE (1 << 3) +#define SSS_TDES_SEL_TDESEEE (3 << 3) +#define SSS_TDES_FIFO_MASK (1 << 5) +#define SSS_TDES_FIFO_OFF (0 << 5) +#define SSS_TDES_FIFO_ON (1 << 5) +#define SSS_TDES_SWAP_MASK (0xF << 6) +#define SSS_TDES_SWAPKEY_OFF (0 << 6) +#define SSS_TDES_SWAPKEY_ON (1 << 6) +#define SSS_TDES_SWAPIV_OFF (0 << 7) +#define SSS_TDES_SWAPIV_ON (1 << 7) +#define SSS_TDES_SWAPDO_OFF (0 << 8) +#define SSS_TDES_SWAPDO_ON (1 << 8) +#define SSS_TDES_SWAPDI_OFF (0 << 9) +#define SSS_TDES_SWAPDI_ON (1 << 9) + +/* TDES status */ +#define SSS_TDES_OUTRDY_MASK (1 << 0) +#define SSS_TDES_OUTRDY_OFF (0 << 0) +#define SSS_TDES_OUTRDY_ON (1 << 0) +#define SSS_TDES_INRDY_MASK (1 << 1) +#define SSS_TDES_INRDY_OFF (0 << 1) +#define SSS_TDES_INRDY_ON (1 << 1) +#define SSS_TDES_BUSY_MASK (1 << 2) +#define SSS_TDES_BUSY_OFF (0 << 2) +#define SSS_TDES_BUSY_ON (1 << 2) + +/* Hash control */ +#define SSS_HASH_ENGSEL_MASK (0xF << 0) +#define SSS_HASH_ENGSEL_SHA1HASH (0x0 << 0) +#define SSS_HASH_ENGSEL_SHA1HMAC (0x1 << 0) +#define SSS_HASH_ENGSEL_SHA1HMACIN (0x1 << 0) +#define SSS_HASH_ENGSEL_SHA1HMACOUT (0x9 << 0) +#define SSS_HASH_ENGSEL_MD5HASH (0x2 << 0) +#define SSS_HASH_ENGSEL_MD5HMAC (0x3 << 0) +#define SSS_HASH_ENGSEL_MD5HMACIN (0x3 << 0) +#define SSS_HASH_ENGSEL_MD5HMACOUT (0xB << 0) +#define SSS_HASH_ENGSEL_SHA256HASH (0x4 << 0) +#define SSS_HASH_ENGSEL_SHA256HMAC (0x5 << 0) +#define SSS_HASH_ENGSEL_PRNG (0x8 << 0) +#define SSS_HASH_STARTBIT_ON (1 << 4) +#define SSS_HASH_USERIV_EN (1 << 5) + +/* Hash control 2 */ +#define SSS_HASH_PAUSE_ON (1 << 0) + +/* Hash control - FIFO mode */ +#define SSS_HASH_FIFO_MASK (1 << 0) +#define SSS_HASH_FIFO_OFF (0 << 0) +#define SSS_HASH_FIFO_ON (1 << 0) + +/* Hash control - byte swap */ +#define SSS_HASH_SWAP_MASK (0xF << 0) +#define SSS_HASH_SWAPKEY_OFF (0 << 0) +#define SSS_HASH_SWAPKEY_ON (1 << 0) +#define SSS_HASH_SWAPIV_OFF (0 << 1) +#define SSS_HASH_SWAPIV_ON (1 << 1) +#define SSS_HASH_SWAPDO_OFF (0 << 2) +#define SSS_HASH_SWAPDO_ON (1 << 2) +#define SSS_HASH_SWAPDI_OFF (0 << 3) +#define SSS_HASH_SWAPDI_ON (1 << 3) + +/* Hash status */ +#define SSS_HASH_BUFRDY_MASK (1 << 0) +#define SSS_HASH_BUFRDY_OFF (0 << 0) +#define SSS_HASH_BUFRDY_ON (1 << 0) +#define SSS_HASH_SEEDSETTING_MASK (1 << 1) +#define SSS_HASH_SEEDSETTING_OFF (0 << 1) +#define SSS_HASH_SEEDSETTING_ON (1 << 1) +#define SSS_HASH_PRNGBUSY_MASK (1 << 2) +#define SSS_HASH_PRNGBUSY_OFF (0 << 2) +#define SSS_HASH_PRNGBUSY_ON (1 << 2) +#define SSS_HASH_PARTIALDONE_MASK (1 << 4) +#define SSS_HASH_PARTIALDONE_OFF (0 << 4) +#define SSS_HASH_PARTIALDONE_ON (1 << 4) +#define SSS_HASH_PRNGDONE_MASK (1 << 5) +#define SSS_HASH_PRNGDONE_OFF (0 << 5) +#define SSS_HASH_PRNGDONE_ON (1 << 5) +#define SSS_HASH_MSGDONE_MASK (1 << 6) +#define SSS_HASH_MSGDONE_OFF (0 << 6) +#define SSS_HASH_MSGDONE_ON (1 << 6) +#define SSS_HASH_PRNGERROR_MASK (1 << 7) +#define SSS_HASH_PRNGERROR_OFF (0 << 7) +#define SSS_HASH_PRNGERROR_ON (1 << 7) + +#endif /* __CRYPTODXE_H__ */ + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.inf new file mode 100644 index 000000000..45ae5fc0a --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/HashDxe/HashDxe.inf @@ -0,0 +1,57 @@ +## @file +# +# Component description file for Crypto engine module +# +# This is the main routine for initializing the Crypto engine support routines. +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashDxe + FILE_GUID = 2ceb319d-ee89-4ef2-9a0d-7958abf4cd87 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = HashDxeInitialize + +[Sources] + HashDxe.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + SamsungPlatformPkg/SamsungPlatformPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UncachedMemoryAllocationLib + DebugLib + IoLib + ArmGicLib + +[Guids] + gEfiHashAlgorithmSha1Guid + gEfiHashAlgorithmSha256Guid + +[Protocols] + gEfiDevicePathProtocolGuid + gEfiHashProtocolGuid + gSamsungPlatformGpioProtocolGuid + +[Pcd] + gExynosPkgTokenSpaceGuid.PcdCmuBase + gExynosPkgTokenSpaceGuid.PcdCryptoBase + +[Depex] + TRUE diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/ComponentName.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/ComponentName.c new file mode 100644 index 000000000..836d0b583 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/ComponentName.c @@ -0,0 +1,231 @@ +/** @file + UEFI Component Name(2) protocol implementation for OHCI driver. + +Copyright (c) 2004 - 2007, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ohci.h" + + +// +// EFI Component Name Protocol +// + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName = { + OhciComponentNameGetDriverName, + OhciComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) OhciComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) OhciComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOhciDriverNameTable[] = { + { "eng;en", L"Usb Ohci Driver" }, + { NULL, NULL } +}; + + +// +// EFI Component Name Functions +// + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mOhciDriverNameTable, + DriverName, + (BOOLEAN)(This == &gOhciComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + USB_HC_DEV *OhciDev; + EFI_USB2_HC_PROTOCOL *Usb2Hc; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver is currently managing ControllerHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gOhciDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsb2HcProtocolGuid, + (VOID **) &Usb2Hc, + gOhciDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + OhciDev = OHC_FROM_USB2_HC_PROTO (Usb2Hc); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + OhciDev->CtrlNameTable, + ControllerName, + (BOOLEAN)(This == &gOhciComponentName) + ); + +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/ComponentName.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/ComponentName.h new file mode 100644 index 000000000..f2f68769a --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/ComponentName.h @@ -0,0 +1,145 @@ +/** @file + + This file contains the delarations for componet name routines. + +Copyright (c) 2008, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _COMPONENT_NAME_H_ +#define _COMPONENT_NAME_H_ + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/Ohci.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/Ohci.c new file mode 100644 index 000000000..d8967a386 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/Ohci.c @@ -0,0 +1,2345 @@ +/** @file + + The OHCI driver model and HC protocol routines. + +Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ohci.h" +#include <Protocol/Cpu.h> + +EFI_CPU_ARCH_PROTOCOL *gCpu; + +EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = { + OhciDriverBindingSupported, + OhciDriverBindingStart, + OhciDriverBindingStop, + 0x30, + NULL, + NULL +}; + +/** + Provides software reset for the USB host controller according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param Attributes A bit mask of the reset operation to perform. See + below for a list of the supported bit mask values. + + @return EFI_SUCCESS The reset operation succeeded. + @return EFI_INVALID_PARAMETER Attributes is not valid. + @return EFI_UNSUPPORTED This type of reset is not currently supported. + @return EFI_DEVICE_ERROR Other errors. + +**/ + +EFI_STATUS +EFIAPI +Ohci2Reset ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT16 Attributes + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + EFI_TPL OldTpl; + UINT32 UsbCtr; + + if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) || + (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) { + return EFI_UNSUPPORTED; + } + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + + OldTpl = gBS->RaiseTPL (OHCI_TPL); + +#if 1 + switch (Attributes) { + case EFI_USB_HC_RESET_GLOBAL: + // + // Stop schedule and set the Global Reset bit in the command register + // + /* + OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + + UsbCtr = OhciReadReg(Ohc, HC_CONTROL_OFFSET); + UsbCtr &= (1<<9); //all except of RWC is clear + OhciWriteReg(Ohc, HC_CONTROL_OFFSET, UsbCtr); + + gBS->Stall (OHC_ROOT_PORT_RECOVERY_STALL);*/ + break; + + case EFI_USB_HC_RESET_HOST_CONTROLLER: + // + // Stop schedule and set Host Controller Reset bit to 1 + // + /* + OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + + UsbCtr = OhciReadReg(Ohc, HC_CONTROL_OFFSET); + UsbCtr &= (1<<9); //all except of RWC is clear + OhciWriteReg(Ohc, HC_CONTROL_OFFSET, UsbCtr);*/ + break; + + default: + goto ON_INVAILD_PARAMETER; + } + + OhcDumpRegs(Ohc); + + // + // Delete all old transactions on the USB bus, then + // reinitialize the frame list + // + OhciFreeAllAsyncReq (Ohc); + OhciDestoryFrameList (Ohc); + OhciInitFrameList (Ohc); + + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + + return EFI_SUCCESS; + +ON_INVAILD_PARAMETER: + + gBS->RestoreTPL (OldTpl); + + return EFI_INVALID_PARAMETER; +#else + switch (Attributes) { + case EFI_USB_HC_RESET_GLOBAL: + // + // Stop schedule and set the Global Reset bit in the command register + // + OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + + OhciSetRegBit (Ohc->PciIo, USBCMD_OFFSET, USBCMD_GRESET); + + gBS->Stall (OHC_ROOT_PORT_RESET_STALL); + + // + // Clear the Global Reset bit to zero. + // + OhciClearRegBit (Ohc->PciIo, USBCMD_OFFSET, USBCMD_GRESET); + + gBS->Stall (OHC_ROOT_PORT_RECOVERY_STALL); + break; + + case EFI_USB_HC_RESET_HOST_CONTROLLER: + // + // Stop schedule and set Host Controller Reset bit to 1 + // + OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + + OhciSetRegBit (Ohc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET); + + gBS->Stall (OHC_ROOT_PORT_RECOVERY_STALL); + break; + + default: + goto ON_INVAILD_PARAMETER; + } + + // + // Delete all old transactions on the USB bus, then + // reinitialize the frame list + // + OhciFreeAllAsyncReq (Ohc); + OhciDestoryFrameList (Ohc); + OhciInitFrameList (Ohc); + + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INIT, "---Ohci2Reset()\n")); + + return EFI_SUCCESS; + +ON_INVAILD_PARAMETER: + + gBS->RestoreTPL (OldTpl); + + return EFI_INVALID_PARAMETER; +#endif +} + + +/** + Retrieves current state of the USB host controller according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param State Variable to receive current device state. + + @return EFI_SUCCESS The state is returned. + @return EFI_INVALID_PARAMETER State is not valid. + @return EFI_DEVICE_ERROR Other errors. + +**/ +EFI_STATUS +EFIAPI +Ohci2GetState ( + IN CONST EFI_USB2_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + UINT16 UsbSts; + UINT16 UsbCmd; + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + Ohc = OHC_FROM_USB2_HC_PROTO (This); +#if 1 + UsbSts = OhciReadReg (Ohc, HC_CONTROL_OFFSET); + UsbSts = (UsbSts>>6) & 0x3; + + if (UsbSts == 3) { + *State = EfiUsbHcStateSuspend; + + } else if (UsbSts == 2) { + *State = EfiUsbHcStateOperational; + } else { + *State = EfiUsbHcStateHalt; + } +#else + UsbCmd = OhciReadReg (Ohc->PciIo, USBCMD_OFFSET); + UsbSts = OhciReadReg (Ohc->PciIo, USBSTS_OFFSET); + + if ((UsbCmd & USBCMD_EGSM) !=0 ) { + *State = EfiUsbHcStateSuspend; + + } else if ((UsbSts & USBSTS_HCH) != 0) { + *State = EfiUsbHcStateHalt; + + } else { + *State = EfiUsbHcStateOperational; + } +#endif + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return EFI_SUCCESS; +} + + +/** + Sets the USB host controller to a specific state according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param State Indicates the state of the host controller that will + be set. + + @return EFI_SUCCESS Host controller was successfully placed in the state. + @return EFI_INVALID_PARAMETER State is invalid. + @return EFI_DEVICE_ERROR Failed to set the state. + +**/ +EFI_STATUS +EFIAPI +Ohci2SetState ( + IN EFI_USB2_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + EFI_USB_HC_STATE CurState; + USB_HC_DEV *Ohc; + EFI_TPL OldTpl; + EFI_STATUS Status; + UINT16 UsbSts; + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + Status = Ohci2GetState (This, &CurState); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (CurState == State) { + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + OldTpl = gBS->RaiseTPL (OHCI_TPL); + + switch (State) { + case EfiUsbHcStateHalt: + Status = OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + break; + + case EfiUsbHcStateOperational: + #if 1 + UsbSts = OhciReadReg (Ohc, HC_CONTROL_OFFSET); + UsbSts &= (1<<9); + UsbSts |= (3<<0) | (2<<6); + OhciWriteReg (Ohc, HC_CONTROL_OFFSET, UsbSts); + + OhcDumpRegs(Ohc); + #else + UsbCmd = OhciReadReg (Ohc->PciIo, USBCMD_OFFSET); + + if (CurState == EfiUsbHcStateHalt) { + // + // Set Run/Stop bit to 1, also set the bandwidht reclamation + // point to 64 bytes + // + UsbCmd |= USBCMD_RS | USBCMD_MAXP; + OhciWriteReg (Ohc->PciIo, USBCMD_OFFSET, UsbCmd); + + } else if (CurState == EfiUsbHcStateSuspend) { + // + // If FGR(Force Global Resume) bit is 0, set it + // + if ((UsbCmd & USBCMD_FGR) == 0) { + UsbCmd |= USBCMD_FGR; + OhciWriteReg (Ohc->PciIo, USBCMD_OFFSET, UsbCmd); + } + + // + // wait 20ms to let resume complete (20ms is specified by OHCI spec) + // + gBS->Stall (OHC_FORCE_GLOBAL_RESUME_STALL); + + // + // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0 + // + UsbCmd &= ~USBCMD_FGR; + UsbCmd &= ~USBCMD_EGSM; + UsbCmd |= USBCMD_RS; + OhciWriteReg (Ohc->PciIo, USBCMD_OFFSET, UsbCmd); + } +#endif + break; + + case EfiUsbHcStateSuspend: + #if 1 + Status = EFI_INVALID_PARAMETER; + #else + Status = Ohci2SetState (This, EfiUsbHcStateHalt); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + // + // Set Enter Global Suspend Mode bit to 1. + // + UsbCmd = OhciReadReg (Ohc->PciIo, USBCMD_OFFSET); + UsbCmd |= USBCMD_EGSM; + OhciWriteReg (Ohc->PciIo, USBCMD_OFFSET, UsbCmd); + #endif + break; + + default: + Status = EFI_INVALID_PARAMETER; + break; + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return Status; +} + +/** + Retrieves capabilities of USB host controller according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param MaxSpeed A pointer to the max speed USB host controller + supports. + @param PortNumber A pointer to the number of root hub ports. + @param Is64BitCapable A pointer to an integer to show whether USB host + controller supports 64-bit memory addressing. + + @return EFI_SUCCESS capabilities were retrieved successfully. + @return EFI_INVALID_PARAMETER MaxSpeed or PortNumber or Is64BitCapable is NULL. + @return EFI_DEVICE_ERROR An error was encountered. + +**/ +EFI_STATUS +EFIAPI +Ohci2GetCapability ( + IN EFI_USB2_HC_PROTOCOL *This, + OUT UINT8 *MaxSpeed, + OUT UINT8 *PortNumber, + OUT UINT8 *Is64BitCapable + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + UINT32 Offset; + UINT16 PortSC; + UINT32 Index; + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + + if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) { + return EFI_INVALID_PARAMETER; + } + + *MaxSpeed = EFI_USB_SPEED_FULL; + *Is64BitCapable = (UINT8) FALSE; + + *PortNumber = 3; +/* + for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) { + Offset = HC_PORT_STATUS_OFFSET + Index * 4; + PortSC = OhciReadReg (Ohc, Offset); + + // + // Port status's bit 7 is reserved and always returns 1 if + // the port number is valid. Intel's UHCI (in EHCI controller) + // returns 0 in this bit if port number is invalid. Also, if + // PciIo IoRead returns error, 0xFFFF is returned to caller. + // + if (((PortSC & 0x80) == 0) || (PortSC == 0xFFFF)) { + break; + } + (*PortNumber)++; + }*/ + + Ohc->RootPorts = *PortNumber; + + DEBUG ((EFI_D_INIT, "Ohci2GetCapability: %d ports\n", (UINT32)Ohc->RootPorts)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return EFI_SUCCESS; +} + + +/** + Retrieves the current status of a USB root hub port according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL. + @param PortNumber The port to get status. + @param PortStatus A pointer to the current port status bits and port + status change bits. + + @return EFI_SUCCESS status of the USB root hub port was returned in PortStatus. + @return EFI_INVALID_PARAMETER PortNumber is invalid. + @return EFI_DEVICE_ERROR Can't read register. + +**/ +EFI_STATUS +EFIAPI +Ohci2GetRootHubPortStatus ( + IN CONST EFI_USB2_HC_PROTOCOL *This, + IN CONST UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + UINT32 Offset; + UINT32 PortSC; + + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + + if (PortStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (PortNumber >= Ohc->RootPorts) { + return EFI_INVALID_PARAMETER; + } + + Offset = HC_PORT_STATUS_OFFSET + PortNumber * 4; + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + PortSC = OhciReadReg (Ohc, Offset); + + if ((PortSC & USBPORTSC_CCS) != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + } + + if ((PortSC & USBPORTSC_PED) != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + } + + if ((PortSC & USBPORTSC_SUSP) != 0) { + DEBUG ((EFI_D_INIT, "Ohci2GetRootHubPortStatus: port %d is suspended\n", PortNumber)); + PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; + } + + if ((PortSC & USBPORTSC_PR) != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_RESET; + } + + if ((PortSC & USBPORTSC_LSDA) != 0) { + PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; + } + + // + // CHC will always return one in port owner bit + // + PortStatus->PortStatus |= USB_PORT_STAT_OWNER; + + if ((PortSC & USBPORTSC_CSC) != 0) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; + } + + if ((PortSC & USBPORTSC_PEDC) != 0) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; + } + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return EFI_SUCCESS; +} + + +/** + Sets a feature for the specified root hub port according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL. + @param PortNumber Specifies the root hub port whose feature is + requested to be set. + @param PortFeature Indicates the feature selector associated with the + feature set request. + + @return EFI_SUCCESS PortFeature was set for the root port. + @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. + @return EFI_DEVICE_ERROR Can't read register. + +**/ +EFI_STATUS +EFIAPI +Ohci2SetRootHubPortFeature ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + EFI_TPL OldTpl; + UINT32 Offset; + UINT32 PortSC; + UINT32 Command; + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + + if (PortNumber >= Ohc->RootPorts) { + return EFI_INVALID_PARAMETER; + } + + Offset = HC_PORT_STATUS_OFFSET + PortNumber * 4; + + OldTpl = gBS->RaiseTPL (OHCI_TPL); + PortSC = OhciReadReg (Ohc, Offset); + + switch (PortFeature) { + case EfiUsbPortSuspend: + /* + Command = OhciReadReg (Ohc, USBCMD_OFFSET); + if ((Command & USBCMD_EGSM) == 0) { + // + // if global suspend is not active, can set port suspend + // + PortSC &= 0xfff5; + PortSC |= USBPORTSC_SUSP; + }*/ + break; + + case EfiUsbPortReset: + //PortSC &= ~0xFFFF0000; + PortSC = USBPORTSC_PR; + break; + + case EfiUsbPortPower: + //PortSC &= ~0xFFFF0000; + PortSC = USBPORTSC_PPS; + break; + + case EfiUsbPortEnable: + //PortSC &= ~0xFFFF0000; + PortSC = USBPORTSC_PED; + break; + + default: + gBS->RestoreTPL (OldTpl); + return EFI_INVALID_PARAMETER; + } + + OhciWriteReg (Ohc, Offset, PortSC); + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + + return EFI_SUCCESS; +} + + +/** + Clears a feature for the specified root hub port according to Uefi 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param PortNumber Specifies the root hub port whose feature is + requested to be cleared. + @param PortFeature Indicates the feature selector associated with the + feature clear request. + + @return EFI_SUCCESS PortFeature was cleared for the USB root hub port. + @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. + @return EFI_DEVICE_ERROR Can't read register. + +**/ +EFI_STATUS +EFIAPI +Ohci2ClearRootHubPortFeature ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + EFI_TPL OldTpl; + UINT32 Offset; + UINT32 PortSC; + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + + if (PortNumber >= Ohc->RootPorts) { + return EFI_INVALID_PARAMETER; + } + + Offset = HC_PORT_STATUS_OFFSET + PortNumber * 4; + + OldTpl = gBS->RaiseTPL (OHCI_TPL); + PortSC = OhciReadReg (Ohc, Offset); + + switch (PortFeature) { + case EfiUsbPortEnable: + //PortSC &= ~0xFFFF0000; + PortSC = USBPORTSC_CCS; + break; + + case EfiUsbPortSuspend: + PortSC = 0; + /* + // + // Cause a resume on the specified port if in suspend mode. + // + PortSC &= ~USBPORTSC_SUSP;*/ + break; + + case EfiUsbPortPower: + PortSC = 0; + //PortSC &= ~0xFFFF0000; + // + // No action + // + break; + + case EfiUsbPortReset: + /*PortSC &= ~0xFFFF0000; + //iky temporary + PortSC |= USBPORTSC_PRSC; + OhciWriteReg (Ohc, Offset, PortSC); + while(OhciReadReg(Ohc, Offset) & USBPORTSC_PRSC); + + PortSC = OhciReadReg (Ohc, Offset); + PortSC |= USBPORTSC_CSC; + PortSC &= ~0xFFFF0000; + OhciWriteReg (Ohc, Offset, PortSC); + + PortSC = OhciReadReg (Ohc, Offset); + PortSC &= ~0xFFFF0000; + PortSC |= USBPORTSC_PED; + //PortSC &= ~USBPORTSC_PR;*/ + break; + + case EfiUsbPortConnectChange: + //PortSC &= ~0xFFFF0000; + //PortSC |= USBPORTSC_CSC; + PortSC = USBPORTSC_CSC; + break; + + case EfiUsbPortEnableChange: + //PortSC &= ~0xFFFF0000; + //PortSC |= USBPORTSC_PEDC; + PortSC = USBPORTSC_PEDC; + break; + + case EfiUsbPortSuspendChange: + // + // Root hub does not support this + // + //PortSC &= ~0xFFFF0000; + break; + + case EfiUsbPortOverCurrentChange: + // + // Root hub does not support this + // + //PortSC &= ~0xFFFF0000; + break; + + case EfiUsbPortResetChange: + // + // Root hub does not support this + // + //PortSC &= ~0xFFFF0000; + break; + + default: + gBS->RestoreTPL (OldTpl); + return EFI_INVALID_PARAMETER; + } + + OhciWriteReg (Ohc, Offset, PortSC); + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + + return EFI_SUCCESS; +} + + +/** + Submits control transfer to a target USB device accroding to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param DeviceAddress Target device address. + @param DeviceSpeed Device speed. + @param MaximumPacketLength Maximum packet size of the target endpoint. + @param Request USB device request to send. + @param TransferDirection Data direction of the Data stage in control transfer. + @param Data Data to transmit/receive in data stage. + @param DataLength Length of the data. + @param TimeOut Maximum time, in microseconds, for transfer to complete. + @param Translator Transaction translator to be used by this device. + @param TransferResult Variable to receive the transfer result. + + @return EFI_SUCCESS The control transfer was completed successfully. + @return EFI_OUT_OF_RESOURCES Failed due to lack of resource. + @return EFI_INVALID_PARAMETER Some parameters are invalid. + @return EFI_TIMEOUT Failed due to timeout. + @return EFI_DEVICE_ERROR Failed due to host controller or device error. + +**/ +EFI_STATUS +EFIAPI +Ohci2ControlTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN TimeOut, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + OHCI_ED_HW *Ed; + EFI_TPL OldTpl; + EFI_STATUS Status; + OHCI_QH_RESULT QhResult; + UINT8 PktId; + UINT8 *RequestPhy; + VOID *RequestMap; + UINT8 *DataPhy; + VOID *DataMap; + BOOLEAN IsSlowDevice; + UINTN TransferDataLength; + + DEBUG((EFI_D_INIT, "+++Ohci2ControlTransfer(DeviceAddr : %d, Data : 0x%p, Datas : %d, Max : %d, Dir : %d)\n", DeviceAddress, Data, *DataLength, MaximumPacketLength, TransferDirection)); + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + Ed = NULL; + DataPhy = NULL; + DataMap = NULL; + RequestPhy = NULL; + RequestMap = NULL; + + IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE); + + // + // Parameters Checking + // + if (Request == NULL || TransferResult == NULL) { + DEBUG((EFI_D_ERROR, "FAIL! NULL point\n")); + return EFI_INVALID_PARAMETER; + } + + //iky ??? + + if (IsSlowDevice && (MaximumPacketLength != 8)) { + DEBUG((EFI_D_ERROR, "FAIL! not matched MaximumPacketLength1\n")); + //MaximumPacketLength = 8; + return EFI_INVALID_PARAMETER; + } + + if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) && + (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) { + DEBUG((EFI_D_ERROR, "FAIL! not matched MaximumPacketLength2\n")); + return EFI_INVALID_PARAMETER; + } + + if ((TransferDirection != EfiUsbNoData) && (Data == NULL || DataLength == NULL)) { + DEBUG((EFI_D_ERROR, "FAIL! no DATA\n")); + return EFI_INVALID_PARAMETER; + } + + if (TransferDirection == EfiUsbNoData) { + TransferDataLength = 0; + } else { + TransferDataLength = *DataLength; + } + + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + + // + // If errors exist that cause host controller halt, + // clear status then return EFI_DEVICE_ERROR. + // + OhciAckAllInterrupt (Ohc); + + if (!OhciIsHcWorking (Ohc)) { + return EFI_DEVICE_ERROR; + } + + OldTpl = gBS->RaiseTPL (OHCI_TPL); + + // + // Map the Request and data for bus master access, + // then create a list of TD for this transfer + // + Status = OhciMapUserRequest (Ohc, Request, &RequestPhy, &RequestMap); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = OhciMapUserData (Ohc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap); + + if (EFI_ERROR (Status)) { + Ohc->PciIo->Unmap (Ohc->PciIo, RequestMap); + goto ON_EXIT; + } + + Ed = OhciCreateCtrlTds ( + Ohc, + DeviceAddress, + PktId, + (UINT8*)Request, + RequestPhy, + (UINT8*)Data, + DataPhy, + TransferDataLength, + (UINT8) MaximumPacketLength, + IsSlowDevice + ); + + if (Ed == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto UNMAP_DATA; + } + + gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)Ed, sizeof(OHCI_ED_HW), EfiCpuFlushTypeWriteBackInvalidate); + { + OHCI_TD_HW *Td = Ed->head_td_ptr; + OHCI_TD_SW *Before = NULL; + OHCI_TD_SW *Current = NULL; + + Ohc->CtrlQh = UsbHcAllocateMem (Ohc->MemPool, sizeof(OHCI_TD_SW)); + Ohc->CtrlQh->TdHw = NULL; + Ohc->CtrlQh->NextTd = NULL; + + Before = Ohc->CtrlQh; + do + { + Current = UsbHcAllocateMem (Ohc->MemPool, sizeof(OHCI_TD_SW)); + Current->TdHw = NULL; + Current->NextTd = NULL; + Before->NextTd = Current; + Before->TdHw = Td; + Before->DataLen = (Td->buffer_end - Td->current_buf_ptr + 1); + Before = Current; + + gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)Td, sizeof(OHCI_TD_HW), EfiCpuFlushTypeWriteBackInvalidate); + } while(Td = Td->next_td); + } + + OhciDumpEd(Ed); + +#if 1 + // + // According to the speed of the end point, link + // the TD to corrosponding queue head, then check + // the execution result + // + OhciLinkTdToQh (Ohc, Ed, 0); + Status = OhciExecuteTransfer (Ohc, Ed, TimeOut, IsSlowDevice, &QhResult); + OhciUnlinkTdFromQh (Ohc->CtrlQh, NULL); + + Ohc->PciIo->Flush (Ohc); + + *TransferResult = QhResult.Result; + + if (DataLength != NULL) { + *DataLength = QhResult.Complete; + } + + OhciDestoryTds (Ohc, Ohc->CtrlQh); + +UNMAP_DATA: + if(DataMap) + { + DEBUG((EFI_D_INIT, "Unmap(DataMap)\n")); + Ohc->PciIo->Unmap (Ohc->PciIo, DataMap); + } + if(RequestMap) + { + DEBUG((EFI_D_INIT, "Unmap(RequestMap)\n")); + Ohc->PciIo->Unmap (Ohc->PciIo, RequestMap); + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + + return Status; +#else + // + // According to the speed of the end point, link + // the TD to corrosponding queue head, then check + // the execution result + // + OhciLinkTdToQh (Ohc, Ed); + Status = OhciExecuteTransfer (Ohc, Ed, TimeOut, IsSlowDevice, &QhResult); + OhciUnlinkTdFromQh (Ohc->CtrlQh, TDs); + + Ohc->PciIo->Flush (Ohc->PciIo); + + *TransferResult = QhResult.Result; + + if (DataLength != NULL) { + *DataLength = QhResult.Complete; + } + + OhciDestoryTds (Ohc, TDs); + +UNMAP_DATA: + Ohc->PciIo->Unmap (Ohc->PciIo, DataMap); + Ohc->PciIo->Unmap (Ohc->PciIo, RequestMap); + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + + return Status; +#endif +} + + +/** + Submits bulk transfer to a bulk endpoint of a USB device. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param DeviceAddress Target device address. + @param EndPointAddress Endpoint number and direction. + @param DeviceSpeed Device speed. + @param MaximumPacketLength Maximum packet size of the target endpoint. + @param DataBuffersNumber Number of data buffers prepared for the transfer. + @param Data Array of pointers to the buffers of data. + @param DataLength On input, size of the data buffer, On output, + actually transferred data size. + @param DataToggle On input, data toggle to use; On output, next data toggle. + @param TimeOut Maximum time out, in microseconds. + @param Translator A pointr to the transaction translator data. + @param TransferResult Variable to receive transfer result. + + @return EFI_SUCCESS The bulk transfer was completed successfully. + @return EFI_OUT_OF_RESOURCES Failed due to lack of resource. + @return EFI_INVALID_PARAMETER Some parameters are invalid. + @return EFI_TIMEOUT Failed due to timeout. + @return EFI_DEVICE_ERROR Failed due to host controller or device error. + +**/ +EFI_STATUS +EFIAPI +Ohci2BulkTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM], + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + EFI_USB_DATA_DIRECTION Direction; + EFI_TPL OldTpl; + USB_HC_DEV *Ohc; + OHCI_TD_HW *TDs; + OHCI_QH_SW *BulkQh; + OHCI_QH_RESULT QhResult; + EFI_STATUS Status; + UINT8 PktId; + UINT8 *DataPhy; + VOID *DataMap; +#if 1 + DEBUG((EFI_D_INIT, "+++Ohci2BulkTransfer()\n")); + DEBUG((EFI_D_INIT, "---Ohci2BulkTransfer()\n")); +#else + Ohc = OHC_FROM_USB2_HC_PROTO (This); + DataPhy = NULL; + DataMap = NULL; + + if (DeviceSpeed == EFI_USB_SPEED_LOW) { + return EFI_INVALID_PARAMETER; + } + + if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((*DataToggle != 1) && (*DataToggle != 0)) { + return EFI_INVALID_PARAMETER; + } + + if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) && + (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) { + return EFI_INVALID_PARAMETER; + } + + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_OUT_OF_RESOURCES; + + // + // If has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + OhciAckAllInterrupt (Ohc); + + if (!OhciIsHcWorking (Ohc->PciIo)) { + return EFI_DEVICE_ERROR; + } + + OldTpl = gBS->RaiseTPL (OHCI_TPL); + + // + // Map the source data buffer for bus master access, + // then create a list of TDs + // + if ((EndPointAddress & 0x80) != 0) { + Direction = EfiUsbDataIn; + } else { + Direction = EfiUsbDataOut; + } + + Status = OhciMapUserData (Ohc, Direction, *Data, DataLength, &PktId, &DataPhy, &DataMap); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = EFI_OUT_OF_RESOURCES; + TDs = OhciCreateBulkOrIntTds ( + Ohc, + DeviceAddress, + EndPointAddress, + PktId, + (UINT8 *)*Data, + DataPhy, + *DataLength, + DataToggle, + (UINT8) MaximumPacketLength, + FALSE + ); + + if (TDs == NULL) { + Ohc->PciIo->Unmap (Ohc->PciIo, DataMap); + goto ON_EXIT; + } + + + // + // Link the TDs to bulk queue head. According to the platfore + // defintion of OHCI_NO_BW_RECLAMATION, BulkQh is either configured + // to do full speed bandwidth reclamation or not. + // + BulkQh = Ohc->BulkQh; + + OhciLinkTdToQh (Ohc, BulkQh, TDs); + Status = OhciExecuteTransfer (Ohc, BulkQh, TDs, TimeOut, FALSE, &QhResult); + OhciUnlinkTdFromQh (BulkQh, TDs); + + Ohc->PciIo->Flush (Ohc->PciIo); + + *TransferResult = QhResult.Result; + *DataToggle = QhResult.NextToggle; + *DataLength = QhResult.Complete; + + OhciDestoryTds (Ohc, TDs); + Ohc->PciIo->Unmap (Ohc->PciIo, DataMap); + +ON_EXIT: + gBS->RestoreTPL (OldTpl); +#endif + return Status; +} + +/** + Submits an asynchronous interrupt transfer to an + interrupt endpoint of a USB device according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param DeviceAddress Target device address. + @param EndPointAddress Endpoint number and direction. + @param DeviceSpeed Device speed. + @param MaximumPacketLength Maximum packet size of the target endpoint. + @param IsNewTransfer If TRUE, submit a new transfer, if FALSE cancel old transfer. + @param DataToggle On input, data toggle to use; On output, next data toggle. + @param PollingInterval Interrupt poll rate in milliseconds. + @param DataLength On input, size of the data buffer, On output, + actually transferred data size. + @param Translator A pointr to the transaction translator data. + @param CallBackFunction Function to call periodically. + @param Context User context. + + @return EFI_SUCCESS Transfer was submitted. + @return EFI_INVALID_PARAMETER Some parameters are invalid. + @return EFI_OUT_OF_RESOURCES Failed due to a lack of resources. + @return EFI_DEVICE_ERROR Can't read register. + +**/ +EFI_STATUS +EFIAPI +Ohci2AsyncInterruptTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle, + IN UINTN PollingInterval, + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, + IN VOID *Context + ) +{ +#if 1 + USB_HC_DEV *Ohc; + OHCI_ED_HW *Ed; + BOOLEAN IsSlowDevice; + OHCI_TD_HW *IntTds; + EFI_TPL OldTpl; + EFI_STATUS Status; + UINT8 *DataPtr; + UINT8 *DataPhy; + UINT8 PktId; + OHCI_QH_RESULT QhResult; + + DEBUG((EFI_D_INIT, "+++Ohci2AsyncInterruptTransfer(EP%d)\n", EndPointAddress)); + + Ohc = OHC_FROM_USB2_HC_PROTO (This); + IntTds = NULL; + DataPtr = NULL; + DataPhy = NULL; + + IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE); + + if ((EndPointAddress & 0x80) == 0) { + DEBUG((EFI_D_ERROR, "FAIL! EndPointAddress ERROR\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Delete Async interrupt transfer request + // + if (!IsNewTransfer) { + OldTpl = gBS->RaiseTPL (OHCI_TPL); + Status = OhciRemoveAsyncReq (Ohc, DeviceAddress, EndPointAddress, DataToggle); + + gBS->RestoreTPL (OldTpl); + return Status; + } + + if (PollingInterval < 1 || PollingInterval > 255) { + DEBUG((EFI_D_ERROR, "FAIL! PollingInterval ERROR\n")); + return EFI_INVALID_PARAMETER; + } + + if (DataLength == 0) { + DEBUG((EFI_D_ERROR, "FAIL! DataLength ERROR\n")); + return EFI_INVALID_PARAMETER; + } + + if ((*DataToggle != 1) && (*DataToggle != 0)) { + DEBUG((EFI_D_ERROR, "FAIL! DataToggle ERROR\n")); + return EFI_INVALID_PARAMETER; + } + + // + // If has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + OhciAckAllInterrupt (Ohc); + + if (!OhciIsHcWorking (Ohc->PciIo)) { + return EFI_DEVICE_ERROR; + } + + if ((EndPointAddress & 0x80) == 0) { + PktId = OUTPUT_PACKET_ID; + } else { + PktId = INPUT_PACKET_ID; + } + + // + // Allocate and map source data buffer for bus master access. + // + DataPtr = UsbHcAllocateMem (Ohc->MemPool, DataLength); + + if (DataPtr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DataPhy = (UINT8 *) (UINTN) UsbHcGetPciAddressForHostMem (Ohc->MemPool, DataPtr, DataLength); + + OldTpl = gBS->RaiseTPL (OHCI_TPL); + + /*Qh = OhciCreateQh (Ohc, PollingInterval); + + if (Qh == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FREE_DATA; + }*/ + + Ed = OhciCreateBulkOrIntTds ( + Ohc, + DeviceAddress, + EndPointAddress, + PktId, + DataPtr, + DataPhy, + DataLength, + DataToggle, + (UINT8) MaximumPacketLength, + IsSlowDevice + ); + + if (Ed == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG((EFI_D_ERROR, "FAIL! OhciCreateBulkOrIntTds ERROR\n")); + goto DESTORY_QH; + } + + gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)Ed, sizeof(OHCI_ED_HW), EfiCpuFlushTypeWriteBackInvalidate); + { + OHCI_TD_HW *Td = Ed->head_td_ptr; + OHCI_TD_SW *Before = NULL; + OHCI_TD_SW *Current = NULL; + + Ohc->IntrQh = UsbHcAllocateMem (Ohc->MemPool, sizeof(OHCI_TD_SW)); + Ohc->IntrQh->TdHw = NULL; + Ohc->IntrQh->NextTd = NULL; + + Before = Ohc->IntrQh; + do + { + Current = UsbHcAllocateMem (Ohc->MemPool, sizeof(OHCI_TD_SW)); + Current->TdHw = NULL; + Current->NextTd = NULL; + Before->NextTd = Current; + Before->TdHw = Td; + Before->TdHw->gtd_info.b.buffer_rounding = 0; + Before->Data = Td->current_buf_ptr; + Before->DataLen = (Td->buffer_end - Td->current_buf_ptr + 1); + Before = Current; + + gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)Td, sizeof(OHCI_TD_HW), EfiCpuFlushTypeWriteBackInvalidate); + } while(Td = Td->next_td); + } + + OhciDumpEd(Ed); + + OhciLinkTdToQh (Ohc, Ed, 1); + + // + // Save QH-TD structures to async Interrupt transfer list, + // for monitor interrupt transfer execution routine use. + // + Status = OhciCreateAsyncReq ( + Ohc, + Ed, + Ohc->IntrQh, + DeviceAddress, + EndPointAddress, + DataLength, + PollingInterval, + DataPtr, + CallBackFunction, + Context, + IsSlowDevice + ); + + if (EFI_ERROR (Status)) { + goto DESTORY_QH; + } + + //OhciLinkQhToFrameList (Ohc, Qh); + + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INIT, "---Ohci2AsyncInterruptTransfer()\n")); + + return EFI_SUCCESS; + +DESTORY_QH: + //UsbHcFreeMem (Ohc->MemPool, Qh, sizeof (OHCI_QH_SW)); + +FREE_DATA: + UsbHcFreeMem (Ohc->MemPool, DataPtr, DataLength); + Ohc->PciIo->Flush (Ohc->PciIo); + + gBS->RestoreTPL (OldTpl); + +#else + Ohc = OHC_FROM_USB2_HC_PROTO (This); + Qh = NULL; + IntTds = NULL; + DataPtr = NULL; + DataPhy = NULL; + + IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE); + + if ((EndPointAddress & 0x80) == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Delete Async interrupt transfer request + // + if (!IsNewTransfer) { + OldTpl = gBS->RaiseTPL (OHCI_TPL); + Status = OhciRemoveAsyncReq (Ohc, DeviceAddress, EndPointAddress, DataToggle); + + gBS->RestoreTPL (OldTpl); + return Status; + } + + if (PollingInterval < 1 || PollingInterval > 255) { + return EFI_INVALID_PARAMETER; + } + + if (DataLength == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((*DataToggle != 1) && (*DataToggle != 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // If has errors that cause host controller halt, + // then return EFI_DEVICE_ERROR directly. + // + OhciAckAllInterrupt (Ohc); + + if (!OhciIsHcWorking (Ohc->PciIo)) { + return EFI_DEVICE_ERROR; + } + + if ((EndPointAddress & 0x80) == 0) { + PktId = OUTPUT_PACKET_ID; + } else { + PktId = INPUT_PACKET_ID; + } + + // + // Allocate and map source data buffer for bus master access. + // + DataPtr = UsbHcAllocateMem (Ohc->MemPool, DataLength); + + if (DataPtr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DataPhy = (UINT8 *) (UINTN) UsbHcGetPciAddressForHostMem (Ohc->MemPool, DataPtr, DataLength); + + OldTpl = gBS->RaiseTPL (OHCI_TPL); + + Qh = OhciCreateQh (Ohc, PollingInterval); + + if (Qh == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FREE_DATA; + } + + IntTds = OhciCreateBulkOrIntTds ( + Ohc, + DeviceAddress, + EndPointAddress, + PktId, + DataPtr, + DataPhy, + DataLength, + DataToggle, + (UINT8) MaximumPacketLength, + IsSlowDevice + ); + + if (IntTds == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto DESTORY_QH; + } + + OhciLinkTdToQh (Ohc, Qh, IntTds); + + // + // Save QH-TD structures to async Interrupt transfer list, + // for monitor interrupt transfer execution routine use. + // + Status = OhciCreateAsyncReq ( + Ohc, + Qh, + IntTds, + DeviceAddress, + EndPointAddress, + DataLength, + PollingInterval, + DataPtr, + CallBackFunction, + Context, + IsSlowDevice + ); + + if (EFI_ERROR (Status)) { + goto DESTORY_QH; + } + + OhciLinkQhToFrameList (Ohc, Qh); + + gBS->RestoreTPL (OldTpl); + + DEBUG((EFI_D_INIT, "---Ohci2AsyncInterruptTransfer()\n")); + + return EFI_SUCCESS; + +DESTORY_QH: + UsbHcFreeMem (Ohc->MemPool, Qh, sizeof (OHCI_QH_SW)); + +FREE_DATA: + UsbHcFreeMem (Ohc->MemPool, DataPtr, DataLength); + Ohc->PciIo->Flush (Ohc->PciIo); + + gBS->RestoreTPL (OldTpl); +#endif +} + +/** + Submits synchronous interrupt transfer to an interrupt endpoint + of a USB device according to UEFI 2.0 spec. + + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param DeviceAddress Target device address. + @param EndPointAddress Endpoint number and direction. + @param DeviceSpeed Device speed. + @param MaximumPacketLength Maximum packet size of the target endpoint. + @param Data Array of pointers to the buffers of data. + @param DataLength On input, size of the data buffer, On output, + actually transferred data size. + @param DataToggle On input, data toggle to use; On output, next data toggle. + @param TimeOut Maximum time out, in microseconds. + @param Translator A pointr to the transaction translator data. + @param TransferResult Variable to receive transfer result. + + @return EFI_SUCCESS The transfer was completed successfully. + @return EFI_OUT_OF_RESOURCES Failed due to lack of resource. + @return EFI_INVALID_PARAMETER Some parameters are invalid. + @return EFI_TIMEOUT Failed due to timeout. + @return EFI_DEVICE_ERROR Failed due to host controller or device error. + +**/ +EFI_STATUS +EFIAPI +Ohci2SyncInterruptTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult + ) +{ + EFI_STATUS Status; + USB_HC_DEV *Ohc; + OHCI_TD_HW *TDs; + OHCI_QH_RESULT QhResult; + EFI_TPL OldTpl; + UINT8 *DataPhy; + VOID *DataMap; + UINT8 PktId; + BOOLEAN IsSlowDevice; +#if 1 + DEBUG((EFI_D_INIT, "+++Ohci2SyncInterruptTransfer()\n")); + DEBUG((EFI_D_INIT, "---Ohci2SyncInterruptTransfer()\n")); +#else + Ohc = OHC_FROM_USB2_HC_PROTO (This); + DataPhy = NULL; + DataMap = NULL; + TDs = NULL; + + if (DeviceSpeed == EFI_USB_SPEED_HIGH) { + return EFI_INVALID_PARAMETER; + } + + IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE); + + if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((EndPointAddress & 0x80) == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((*DataToggle != 1) && (*DataToggle != 0)) { + return EFI_INVALID_PARAMETER; + } + + if ((*DataLength == 0) || (MaximumPacketLength > 64)) { + return EFI_INVALID_PARAMETER; + } + + if (IsSlowDevice && (MaximumPacketLength > 8)) { + return EFI_INVALID_PARAMETER; + } + + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + + + OhciAckAllInterrupt (Ohc); + + if (!OhciIsHcWorking (Ohc->PciIo)) { + return Status; + } + + OldTpl = gBS->RaiseTPL (OHCI_TPL); + + // + // Map the source data buffer for bus master access. + // Create Tds list, then link it to the OHC's interrupt list + // + Status = OhciMapUserData ( + Ohc, + EfiUsbDataIn, + Data, + DataLength, + &PktId, + &DataPhy, + &DataMap + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + TDs = OhciCreateBulkOrIntTds ( + Ohc, + DeviceAddress, + EndPointAddress, + PktId, + (UINT8 *)Data, + DataPhy, + *DataLength, + DataToggle, + (UINT8) MaximumPacketLength, + IsSlowDevice + ); + + if (TDs == NULL) { + Ohc->PciIo->Unmap (Ohc->PciIo, DataMap); + + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + + OhciLinkTdToQh (Ohc, Ohc->SyncIntQh, TDs); + + Status = OhciExecuteTransfer (Ohc, Ohc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult); + + OhciUnlinkTdFromQh (Ohc->SyncIntQh, TDs); + Ohc->PciIo->Flush (Ohc->PciIo); + + *TransferResult = QhResult.Result; + *DataToggle = QhResult.NextToggle; + *DataLength = QhResult.Complete; + + OhciDestoryTds (Ohc, TDs); + Ohc->PciIo->Unmap (Ohc->PciIo, DataMap); + +ON_EXIT: + gBS->RestoreTPL (OldTpl); +#endif + return Status; +} + + +/** + Submits isochronous transfer to a target USB device according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param DeviceAddress Target device address. + @param EndPointAddress Endpoint number and direction. + @param DeviceSpeed Device speed. + @param MaximumPacketLength Maximum packet size of the target endpoint. + @param DataBuffersNumber Number of data buffers prepared for the transfer. + @param Data Array of pointers to the buffers of data. + @param DataLength On input, size of the data buffer, On output, + actually transferred data size. + @param Translator A pointr to the transaction translator data. + @param TransferResult Variable to receive transfer result. + + @return EFI_UNSUPPORTED + +**/ +EFI_STATUS +EFIAPI +Ohci2IsochronousTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult + ) +{ + DEBUG((EFI_D_INIT, "+++Ohci2IsochronousTransfer()\n")); + DEBUG((EFI_D_INIT, "---Ohci2IsochronousTransfer()\n")); + return EFI_UNSUPPORTED; +} + + +/** + Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec. + + @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. + @param DeviceAddress Target device address. + @param EndPointAddress Endpoint number and direction. + @param DeviceSpeed Device speed. + @param MaximumPacketLength Maximum packet size of the target endpoint. + @param DataBuffersNumber Number of data buffers prepared for the transfer. + @param Data Array of pointers to the buffers of data. + @param DataLength On input, size of the data buffer, On output, + actually transferred data size. + @param Translator A pointr to the transaction translator data. + @param IsochronousCallBack Function to call when the transfer complete. + @param Context Pass to the call back function as parameter. + + @return EFI_UNSUPPORTED + +**/ +EFI_STATUS +EFIAPI +Ohci2AsyncIsochronousTransfer ( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context + ) +{ + DEBUG((EFI_D_INIT, "+++Ohci2AsyncIsochronousTransfer()\n")); + DEBUG((EFI_D_INIT, "---Ohci2AsyncIsochronousTransfer()\n")); + return EFI_UNSUPPORTED; +} + +/** + Entry point for EFI drivers. + + @param ImageHandle EFI_HANDLE. + @param SystemTable EFI_SYSTEM_TABLE. + + @retval EFI_SUCCESS Driver is successfully loaded. + @return Others Failed. + +**/ +EFI_STATUS +EFIAPI +OhciDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS status; + DEBUG((EFI_D_INIT, "+++OhciDriverEntryPoint()\n")); + + status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gOhciDriverBinding, + ImageHandle, + &gOhciComponentName, + &gOhciComponentName2 + ); + + DEBUG((EFI_D_INIT, "---OhciDriverEntryPoint(%r)\n", status)); + + return status; +} + + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has UsbHcProtocol installed will be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +OhciDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + EFI_STATUS OpenStatus; + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_CLASSC UsbClassCReg; + + // + // Test whether there is PCI IO Protocol attached on the controller handle. + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (OpenStatus)) { + DEBUG((EFI_D_ERROR, "--%a(OpenProtocol Error):%d\n", __FUNCTION__, __LINE__)); + return OpenStatus; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); + + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "--%a(Pci.Read Error):%d\n", __FUNCTION__, __LINE__)); + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Test whether the controller belongs to OHCI type + // + if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || + (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) || + (UsbClassCReg.ProgInterface != PCI_IF_OHCI) + ) { + DEBUG ((EFI_D_ERROR, "FAIL! INTERFACE IS NOT OHCI(%X, %X, %X, %X, %X, %X)\n", + UsbClassCReg.BaseCode, + PCI_CLASS_SERIAL, + UsbClassCReg.SubClassCode, + PCI_CLASS_SERIAL_USB, + UsbClassCReg.ProgInterface, + PCI_IF_OHCI + )); + Status = EFI_UNSUPPORTED; + } + +ON_EXIT: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + DEBUG((EFI_D_INIT, "OhciDriverBindingSupported(%r)\n", Status)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + + return Status; + +} + + +/** + Allocate and initialize the empty OHCI device. + + @param PciIo The PCIIO to use. + @param OriginalPciAttributes The original PCI attributes. + + @return Allocated OHCI device. If err, return NULL. + +**/ +USB_HC_DEV * +OhciAllocateDev ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT64 OriginalPciAttributes + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + EFI_STATUS Status; + UINT32 i; + + Ohc = AllocateZeroPool (sizeof (USB_HC_DEV)); + + if (Ohc == NULL) { + return NULL; + } + + // + // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL. + // USB_HC_PROTOCOL is for EFI 1.1 backward compability. + // + Ohc->Signature = USB_HC_DEV_SIGNATURE; + Ohc->Usb2Hc.GetCapability = Ohci2GetCapability; + Ohc->Usb2Hc.Reset = Ohci2Reset; + Ohc->Usb2Hc.GetState = Ohci2GetState; + Ohc->Usb2Hc.SetState = Ohci2SetState; + Ohc->Usb2Hc.ControlTransfer = Ohci2ControlTransfer; + Ohc->Usb2Hc.BulkTransfer = Ohci2BulkTransfer; + Ohc->Usb2Hc.AsyncInterruptTransfer = Ohci2AsyncInterruptTransfer; + Ohc->Usb2Hc.SyncInterruptTransfer = Ohci2SyncInterruptTransfer; + Ohc->Usb2Hc.IsochronousTransfer = Ohci2IsochronousTransfer; + Ohc->Usb2Hc.AsyncIsochronousTransfer = Ohci2AsyncIsochronousTransfer; + Ohc->Usb2Hc.GetRootHubPortStatus = Ohci2GetRootHubPortStatus; + Ohc->Usb2Hc.SetRootHubPortFeature = Ohci2SetRootHubPortFeature; + Ohc->Usb2Hc.ClearRootHubPortFeature = Ohci2ClearRootHubPortFeature; + Ohc->Usb2Hc.MajorRevision = 0x1; + Ohc->Usb2Hc.MinorRevision = 0x1; + + Ohc->Destory = NULL; + Ohc->PciIo = PciIo; + Ohc->OriginalPciAttributes = OriginalPciAttributes; + Ohc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0); + + if (Ohc->MemPool == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + InitializeListHead (&Ohc->AsyncIntList); + + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OhciMonitorAsyncReqList, + Ohc, + &Ohc->AsyncIntMonitor + ); + + if (EFI_ERROR (Status)) { + UsbHcFreeMemPool (Ohc->MemPool); + goto ON_ERROR; + } + + for(i=0; i<15; ++i) + { + Ohc->EdHw[i] = OhciCreateEd(Ohc, 0, 0, 0, 0); + } + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + + return Ohc; + +ON_ERROR: + FreePool (Ohc); + return NULL; +} + + +/** + Free the OHCI device and release its associated resources. + + @param Ohc The OHCI device to release. + +**/ +VOID +OhciFreeDev ( + IN USB_HC_DEV *Ohc + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + + if (Ohc->AsyncIntMonitor != NULL) { + gBS->CloseEvent (Ohc->AsyncIntMonitor); + } + + if (Ohc->ExitBootServiceEvent != NULL) { + gBS->CloseEvent (Ohc->ExitBootServiceEvent); + } + + if (Ohc->MemPool != NULL) { + UsbHcFreeMemPool (Ohc->MemPool); + } + + if (Ohc->CtrlNameTable != NULL) { + FreeUnicodeStringTable (Ohc->CtrlNameTable); + } + + FreePool (Ohc); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); +} + + +/** + Uninstall all Ohci Interface. + + @param Controller Controller handle. + @param This Protocol instance pointer. + +**/ +VOID +OhciCleanDevUp ( + IN EFI_HANDLE Controller, + IN EFI_USB2_HC_PROTOCOL *This + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + + // + // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller + // + Ohc = OHC_FROM_USB2_HC_PROTO (This); + OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + + gBS->UninstallProtocolInterface ( + Controller, + &gEfiUsb2HcProtocolGuid, + &Ohc->Usb2Hc + ); + + OhciFreeAllAsyncReq (Ohc); + OhciDestoryFrameList (Ohc); + + // + // Restore original PCI attributes + // + Ohc->PciIo->Attributes ( + Ohc->PciIo, + EfiPciIoAttributeOperationSet, + Ohc->OriginalPciAttributes, + NULL + ); + + OhciFreeDev (Ohc); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); +} + +/** + One notified function to stop the Host Controller when gBS->ExitBootServices() called. + + @param Event Pointer to this event + @param Context Event hanlder private data + +**/ +VOID +EFIAPI +OhcExitBootService ( + EFI_EVENT Event, + VOID *Context + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + USB_HC_DEV *Ohc; + + Ohc = (USB_HC_DEV *) Context; + + // + // Stop the Host Controller + // + OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + + // + // Reset the Host Controller + // + OhciSetRegBit (Ohc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET); + gBS->Stall (OHC_ROOT_PORT_RECOVERY_STALL); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); +} + +/** + Starting the Usb OHCI Driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + EFI_OUT_OF_RESOURCES- Failed due to resource shortage. + +**/ +EFI_STATUS +EFIAPI +OhciDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_HC_DEV *Ohc; + UINT64 Supports; + UINT64 OriginalPciAttributes; + BOOLEAN PciAttributesSaved; + UINT32 CmdStatus; + UINT32 Buffer; + + // + // Open PCIIO, then enable the EHC device and turn off emulation + // + Ohc = NULL; + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "FAIL! OpenProtocol\n")); + return Status; + } + + PciAttributesSaved = FALSE; + // + // Save original PCI attributes + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationGet, + 0, + &OriginalPciAttributes + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "FAIL! Attributes\n")); + goto CLOSE_PCIIO; + } + PciAttributesSaved = TRUE; + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + if (!EFI_ERROR (Status)) { + Supports &= EFI_PCI_DEVICE_ENABLE; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + } + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "OhcDriverBindingStart: failed to enable controller\n")); + goto CLOSE_PCIIO; + } + + gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu); + + Ohc = OhciAllocateDev (PciIo, OriginalPciAttributes); + + if (Ohc == NULL) { + DEBUG ((EFI_D_ERROR, "FAIL OhciAllocateDev \n")); + Status = EFI_OUT_OF_RESOURCES; + goto CLOSE_PCIIO; + } + + DEBUG ((EFI_D_ERROR, "OHCI SetTimer\n")); + Status = gBS->SetTimer ( + Ohc->AsyncIntMonitor, + TimerPeriodic, + OHC_ASYNC_POLL_INTERVAL + ); + + if (EFI_ERROR (Status)) { + goto FREE_OHC; + } + + // + // Install USB2_HC_PROTOCOL + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiUsb2HcProtocolGuid, + &Ohc->Usb2Hc, + NULL + ); + + if (EFI_ERROR (Status)) { + goto FREE_OHC; + } + + // + // Create event to stop the HC when exit boot service. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OhcExitBootService, + Ohc, + &gEfiEventExitBootServicesGuid, + &Ohc->ExitBootServiceEvent + ); + if (EFI_ERROR (Status)) { + goto UNINSTALL_USBHC; + } + + // + // Install the component name protocol + // + Ohc->CtrlNameTable = NULL; + + AddUnicodeString2 ( + "eng", + gOhciComponentName.SupportedLanguages, + &Ohc->CtrlNameTable, + L"Usb Universal Host Controller", + TRUE + ); + AddUnicodeString2 ( + "en", + gOhciComponentName2.SupportedLanguages, + &Ohc->CtrlNameTable, + L"Usb Universal Host Controller", + FALSE + ); + + + // + // Start the OHCI hardware, also set its reclamation point to 64 bytes + // + //take ownership + +// OhcDumpRegs(Ohc); + + CmdStatus = OhciReadReg(Ohc, HC_COM_STATUS_OFFSET); + OhciWriteReg(Ohc, HC_COM_STATUS_OFFSET, (CmdStatus | (1<<3))); + + do + { + gBS->Stall(1000); + CmdStatus = OhciReadReg(Ohc, HC_COM_STATUS_OFFSET); + } while((CmdStatus & (1<<3))); + + //interrupt disable + OhciWriteReg(Ohc, HC_INT_DISABLE_OFFSET, 0xFFFFFFFF); + + //interrupt status clear + CmdStatus = OhciReadReg(Ohc, HC_INT_STATUS_OFFSET); + OhciWriteReg(Ohc, HC_INT_STATUS_OFFSET, CmdStatus); + + //frame interval + CmdStatus = OhciReadReg(Ohc, HC_FMINTERVAL_OFFSET); + CmdStatus &= 0x8000FFFF; + CmdStatus |= (0x800<<16); //256*8 + OhciWriteReg(Ohc, HC_FMINTERVAL_OFFSET, CmdStatus); + + //set hcca base + // + // Allocate and Init Host Controller's Frame List Entry + // + + #if 1 + Buffer = UsbHcAllocateMem (Ohc->MemPool, sizeof(OHCI_HCCA)); + ZeroMem (Buffer, sizeof(OHCI_HCCA)); + OhciWriteReg(Ohc, HC_HCCA_OFFSET, (UINT32)Buffer); + #else + Status = OhciInitFrameList (Ohc); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "FAIL OhciInitFrameList\n")); + Status = EFI_OUT_OF_RESOURCES; + goto FREE_OHC; + } + #endif + + //Set opertional state + CmdStatus = OhciReadReg(Ohc, HC_CONTROL_OFFSET); + CmdStatus &= ~(3<<6); + CmdStatus |= (2<<6); + OhciWriteReg(Ohc, HC_CONTROL_OFFSET, CmdStatus); + + //setPowerSwitchingMode off + CmdStatus = OhciReadReg(Ohc, HC_RH_DESCRIPTORA_OFFSET); + CmdStatus &= ~(1<<8); + OhciWriteReg(Ohc, HC_RH_DESCRIPTORA_OFFSET, CmdStatus); + + //Set global power + CmdStatus = OhciReadReg(Ohc, HC_RH_STATUS_OFFSET); + CmdStatus |= (1<<16); + OhciWriteReg(Ohc, HC_RH_STATUS_OFFSET, CmdStatus); + + OhcDumpRegs(Ohc); + + DEBUG((EFI_D_INFO, "--%a(EFI_SUCCESS):%d\n", __FUNCTION__, __LINE__)); + + return EFI_SUCCESS; + +UNINSTALL_USBHC: + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiUsb2HcProtocolGuid, + &Ohc->Usb2Hc, + NULL + ); + +FREE_OHC: + OhciFreeDev (Ohc); + +CLOSE_PCIIO: + if (PciAttributesSaved) { + // + // Restore original PCI attributes + // + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + OriginalPciAttributes, + NULL + ); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return Status; +} + + +/** + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +OhciDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + EFI_USB2_HC_PROTOCOL *Usb2Hc; + EFI_STATUS Status; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsb2HcProtocolGuid, + (VOID **) &Usb2Hc, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + // + // Test whether the Controller handler passed in is a valid + // Usb controller handle that should be supported, if not, + // return the error status directly + // + if (EFI_ERROR (Status)) { + return Status; + } + + OhciCleanDevUp (Controller, Usb2Hc); + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return EFI_SUCCESS; +} + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/Ohci.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/Ohci.h new file mode 100644 index 000000000..e84e5e868 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/Ohci.h @@ -0,0 +1,229 @@ +/** @file + + The definition for OHCI driver model and HC protocol routines. + +Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_OHCI_H_ +#define _EFI_OHCI_H_ + + +#include <Uefi.h> + +#include <Protocol/Usb2HostController.h> +#include <Protocol/UsbHostController.h> +#include <Protocol/PciIo.h> + +#include <Guid/EventGroup.h> + +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> + +#include <IndustryStandard/Pci.h> + +typedef struct _USB_HC_DEV USB_HC_DEV; + +#include "UsbHcMem.h" +#include "OhciQueue.h" +#include "OhciReg.h" +#include "OhciSched.h" +#include "OhciDebug.h" +#include "ComponentName.h" + +// +// OHC timeout experience values +// + +#define OHC_1_MICROSECOND 1 +#define OHC_1_MILLISECOND (1000 * OHC_1_MICROSECOND) +#define OHC_1_SECOND (1000 * OHC_1_MILLISECOND) + +// +// OHCI register operation timeout, set by experience +// +#define OHC_GENERIC_TIMEOUT OHC_1_SECOND + +// +// Wait for force global resume(FGR) complete, refers to +// specification[OHCI11-2.1.1] +// +#define OHC_FORCE_GLOBAL_RESUME_STALL (20 * OHC_1_MILLISECOND) + +// +// Wait for roothub port reset and recovery, reset stall +// is set by experience, and recovery stall refers to +// specification[OHCI11-2.1.1] +// +#define OHC_ROOT_PORT_RESET_STALL (50 * OHC_1_MILLISECOND) +#define OHC_ROOT_PORT_RECOVERY_STALL (10 * OHC_1_MILLISECOND) + +// +// Sync and Async transfer polling interval, set by experience, +// and the unit of Async is 100us. +// +#define OHC_SYNC_POLL_INTERVAL (1 * OHC_1_MILLISECOND) +#define OHC_ASYNC_POLL_INTERVAL (50 * 10000UL) + +// +// OHC raises TPL to TPL_NOTIFY to serialize all its operations +// to protect shared data structures. +// +#define OHCI_TPL TPL_NOTIFY + +#define USB_HC_DEV_SIGNATURE SIGNATURE_32 ('u', 'h', 'c', 'i') + +#pragma pack(1) +typedef struct { + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; +} USB_CLASSC; +#pragma pack() + +#define OHC_FROM_USB2_HC_PROTO(This) CR(This, USB_HC_DEV, Usb2Hc, USB_HC_DEV_SIGNATURE) + +// +// USB_HC_DEV support the OHCI hardware controller. It schedules +// the asynchronous interrupt transfer with the same method as +// EHCI: a reversed tree structure. For synchronous interrupt, +// control and bulk transfer, it uses three static queue head to +// schedule them. SyncIntQh is for interrupt transfer. LsCtrlQh is +// for LOW speed control transfer, and FsCtrlBulkQh is for FULL +// speed control or bulk transfer. This is because FULL speed contrl +// or bulk transfer can reclaim the unused bandwidth. Some USB +// device requires this bandwidth reclamation capability. +// +struct _USB_HC_DEV { + UINT32 Signature; + EFI_USB2_HC_PROTOCOL Usb2Hc; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 OriginalPciAttributes; + + // + // Schedule data structures + // + OHCI_HCCA *Hcca; + UINT32 *HccaMapping; + + + UINT32 *FrameBase; // the buffer pointed by this pointer is used to store pci bus address of the QH descriptor. + UINT32 *FrameBaseHostAddr; // the buffer pointed by this pointer is used to store host memory address of the QH descriptor. + + OHCI_TD_SW *CtrlQh; + OHCI_TD_SW *IntrQh; + + OHCI_TD_HW *LastTd; + + OHCI_ED_HW *EdHw[15]; + + UINT32 *Destory; + UINT32 DestroySize; + // + // Structures to maintain asynchronus interrupt transfers. + // When asynchronous interrutp transfer is unlinked from + // the frame list, the hardware may still hold a pointer + // to it. To synchronize with hardware, its resoureces are + // released in two steps using Recycle and RecycleWait. + // Check the asynchronous interrupt management routines. + // + LIST_ENTRY AsyncIntList; + EFI_EVENT AsyncIntMonitor; + OHCI_ASYNC_REQUEST *Recycle; + OHCI_ASYNC_REQUEST *RecycleWait; + + + UINTN RootPorts; + USBHC_MEM_POOL *MemPool; + EFI_UNICODE_STRING_TABLE *CtrlNameTable; + VOID *FrameMapping; + + // + // ExitBootServicesEvent is used to stop the EHC DMA operation + // after exit boot service. + // + EFI_EVENT ExitBootServiceEvent; +}; + +extern EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2; + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has UsbHcProtocol installed will be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +OhciDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starting the Usb OHCI Driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + EFI_OUT_OF_RESOURCES- Failed due to resource shortage. + +**/ +EFI_STATUS +EFIAPI +OhciDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +OhciDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDebug.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDebug.c new file mode 100644 index 000000000..fca45cc06 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDebug.c @@ -0,0 +1,181 @@ +/** @file + + This file provides the information dump support for Ohci when in debug mode. + +Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ohci.h" + + +#ifdef EFI_D_INIT +#undef EFI_D_INIT +#define EFI_D_INIT EFI_D_INFO +#endif + +/** + Dump the content of QH structure. + + @param QhSw Pointer to software QH structure. + +**/ +#if 0 +VOID +OhciDumpQh ( + IN OHCI_QH_SW *QhSw + ) +{ + DEBUG ((EFI_D_INFO, "&QhSw @ 0x%p\n", QhSw)); + DEBUG ((EFI_D_INFO, "QhSw.NextQh - 0x%p\n", QhSw->NextQh)); + DEBUG ((EFI_D_INFO, "QhSw.TDs - 0x%p\n", QhSw->TDs)); + DEBUG ((EFI_D_INFO, "QhSw.QhHw:\n")); + DEBUG ((EFI_D_INFO, " Horizon Link - %x\n", QhSw->QhHw.HorizonLink)); + DEBUG ((EFI_D_INFO, " Vertical Link - %x\n\n", QhSw->QhHw.VerticalLink)); +} +#endif + +/** + Dump the content of TD structure. + + @param TdSw Pointer to software TD structure. + +**/ +VOID +OhciDumpTdHw ( + IN OHCI_TD_HW *TdSw + ) +{ + OHCI_TD_HW *CurTdSw; + + DEBUG ((EFI_D_INIT, "\n+++OhciDumpTds()\n")); + + CurTdSw = TdSw; + + while (CurTdSw != NULL) { + DEBUG ((EFI_D_INIT, " TdHw @ 0x%p\n", CurTdSw)); + DEBUG ((EFI_D_INIT, "TdHw.NextTd - 0x%p\n", CurTdSw->next_td)); + DEBUG ((EFI_D_INIT, "TdHw.StartPtr - 0x%p\n", CurTdSw->current_buf_ptr)); + DEBUG ((EFI_D_INIT, "TdHw.EndPtr - 0x%p\n", CurTdSw->buffer_end)); + DEBUG ((EFI_D_INIT, "gtd_info:\n")); + DEBUG ((EFI_D_INIT, " buffer_rounding - 0x%x\n", CurTdSw->gtd_info.b.buffer_rounding)); + DEBUG ((EFI_D_INIT, " pid - 0x%x\n", CurTdSw->gtd_info.b.pid)); + DEBUG ((EFI_D_INIT, " error_count - 0x%x\n", CurTdSw->gtd_info.b.error_count)); + DEBUG ((EFI_D_INIT, " condition_code - 0x%x\n", CurTdSw->gtd_info.b.condition_code)); + DEBUG ((EFI_D_INIT, " data_toggle - 0x%x\n", CurTdSw->gtd_info.b.data_toggle)); + + CurTdSw = CurTdSw->next_td; + } + + DEBUG ((EFI_D_INIT, "---OhciDumpTds()\n")); +} + +VOID +OhciDumpEd ( + IN OHCI_ED_HW *EdHw + ) +{ + DEBUG ((EFI_D_INIT, "\n+++OhciDumpEd()\n")); + + DEBUG ((EFI_D_INIT, "ed_info:\n")); + DEBUG ((EFI_D_INIT, " func_addr - 0x%x\n", EdHw->ed_info.b.func_addr)); + DEBUG ((EFI_D_INIT, " ep_num - 0x%x\n", EdHw->ed_info.b.ep_num)); + DEBUG ((EFI_D_INIT, " direction - 0x%x\n", EdHw->ed_info.b.direction)); + DEBUG ((EFI_D_INIT, " speed - 0x%x\n", EdHw->ed_info.b.speed)); + DEBUG ((EFI_D_INIT, " skip - 0x%x\n", EdHw->ed_info.b.skip)); + DEBUG ((EFI_D_INIT, " format - 0x%x\n", EdHw->ed_info.b.format)); + DEBUG ((EFI_D_INIT, " mps - 0x%x\n", EdHw->ed_info.b.mps)); + + OhciDumpTdHw(EdHw->head_td_ptr); + + DEBUG ((EFI_D_INIT, "---OhciDumpEd()\n\n")); +} + +VOID +OhciDumpSWTds ( + IN OHCI_TD_SW *TdSw + ) +{ + OHCI_TD_SW *CurTdSw; + OHCI_TD_HW *TdHw; + + DEBUG ((EFI_D_INIT, "\n+++OhciDumpSWTds()\n")); + + CurTdSw = TdSw; + TdHw = CurTdSw->TdHw; + + while (TdHw != NULL) { + DEBUG ((EFI_D_INIT, " TdHw @ 0x%p\n", TdHw)); + DEBUG ((EFI_D_INIT, "TdHw.NextTd - 0x%p\n", TdHw->next_td)); + DEBUG ((EFI_D_INIT, "TdHw.StartPtr - 0x%p\n", TdHw->current_buf_ptr)); + DEBUG ((EFI_D_INIT, "TdHw.EndPtr - 0x%p\n", TdHw->buffer_end)); + DEBUG ((EFI_D_INIT, "TdSw.DataLen - 0x%p\n", CurTdSw->DataLen)); + DEBUG ((EFI_D_INIT, "gtd_info:\n")); + DEBUG ((EFI_D_INIT, " buffer_rounding - 0x%x\n", TdHw->gtd_info.b.buffer_rounding)); + DEBUG ((EFI_D_INIT, " pid - 0x%x\n", TdHw->gtd_info.b.pid)); + DEBUG ((EFI_D_INIT, " error_count - 0x%x\n", TdHw->gtd_info.b.error_count)); + DEBUG ((EFI_D_INIT, " condition_code - 0x%x\n", TdHw->gtd_info.b.condition_code)); + DEBUG ((EFI_D_INIT, " data_toggle - 0x%x\n", TdHw->gtd_info.b.data_toggle)); + + CurTdSw = CurTdSw->NextTd; + TdHw = CurTdSw->TdHw; + } + + DEBUG ((EFI_D_INIT, "---OhciDumpSWTds()\n\n")); +} + +VOID +OhcDumpRegs ( + IN USB_HC_DEV *Ohc + ) +{ + UINT8 Index; + + DEBUG ((EFI_D_INIT, " HC_REVISION_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_REVISION_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_CONTROL_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_CONTROL_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_COM_STATUS_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_COM_STATUS_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_HCCA_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_HCCA_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_FMINTERVAL_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_FMINTERVAL_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_INT_DISABLE_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_INT_DISABLE_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_INT_STATUS_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_INT_STATUS_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_CTRL_HEADED_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_CTRL_HEADED_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_CTRL_CURRED_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_CTRL_CURRED_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_BULK_HEADED_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_BULK_HEADED_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_BULK_CURRED_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_BULK_CURRED_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_RH_STATUS_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_RH_STATUS_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_RH_DESCRIPTORA_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_RH_DESCRIPTORA_OFFSET))); + DEBUG ((EFI_D_INIT, " HC_RH_DESCRIPTORB_OFFSET = 0x%08x\n", OhciReadReg (Ohc, HC_RH_DESCRIPTORB_OFFSET))); + + for (Index = 0; Index <3; Index++) { + DEBUG ((EFI_D_INIT, " HC_PORT_STATUS_OFFSET(%d) = 0x%08x\n", Index, OhciReadReg (Ohc, HC_PORT_STATUS_OFFSET + (4 * Index)))); + } +} + +VOID +OhcDumpRequest ( + IN EFI_USB_DEVICE_REQUEST *Request + ) +{ + DEBUG ((EFI_D_INIT, "RequestType = 0x%X\n", Request->RequestType)); + DEBUG ((EFI_D_INIT, "Request = 0x%X\n", Request->Request)); + DEBUG ((EFI_D_INIT, "Value = 0x%X\n", Request->Value)); + DEBUG ((EFI_D_INIT, "Index = 0x%X\n", Request->Index)); + DEBUG ((EFI_D_INIT, "Length = 0x%X\n", Request->Length)); +} + +VOID +OhcDumpResult ( + IN OHCI_QH_RESULT *Result + ) +{ + DEBUG ((EFI_D_INIT, "Result = 0x%X\n", Result->Result)); + DEBUG ((EFI_D_INIT, "Complete = 0x%X\n", Result->Complete)); + DEBUG ((EFI_D_INIT, "NextToggle = 0x%X\n", Result->NextToggle)); +}
\ No newline at end of file diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDebug.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDebug.h new file mode 100644 index 000000000..8155fcc7d --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDebug.h @@ -0,0 +1,51 @@ +/** @file + + This file contains the definination for host controller debug support routines + +Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_OHCI_DEBUG_H_ +#define _EFI_OHCI_DEBUG_H_ + + +/** + Dump the content of QH structure. + + @param QhSw Pointer to software QH structure. + + @return None. + +**/ +VOID +OhciDumpQh ( + IN OHCI_QH_SW *QhSw + ); + + +/** + Dump the content of TD structure. + + @param TdSw Pointer to software TD structure. + + @return None. + +**/ +VOID +OhciDumpTds ( + IN OHCI_TD_HW *TdSw + ); + +VOID +OhcDumpRegs ( + IN USB_HC_DEV *Ohc + ); +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDxe.inf new file mode 100644 index 000000000..344e9cd9c --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciDxe.inf @@ -0,0 +1,88 @@ +## @file +# +# Component Description File For OhciDxe Module. +# +# OhciDxe driver is responsible for managing the behavior of OHCI controller. +# It implements the interfaces of monitoring the status of all ports and transferring +# Control, Bulk, Interrupt and Isochronous requests to Usb1.x device +# +# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OhciDxe + FILE_GUID = 2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = OhciDriverEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = gOhciDriverBinding +# COMPONENT_NAME = gOhciComponentName +# COMPONENT_NAME2 = gOhciComponentName2 +# + +[Sources] + OhciSched.c + OhciDebug.c + UsbHcMem.h + OhciDebug.h + OhciQueue.c + OhciReg.c + UsbHcMem.c + OhciQueue.h + Ohci.c + Ohci.h + OhciReg.h + OhciSched.h + ComponentName.c + ComponentName.h + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport ## SOMETIME_CONSUMES (enable/disable usb legacy support.) + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + PcdLib + +[Guids] + gEfiEventExitBootServicesGuid ## PRODUCES ## Event + +[Protocols] + gEfiPciIoProtocolGuid ## TO_START + gEfiUsb2HcProtocolGuid ## BY_START + gEfiCpuArchProtocolGuid + +# [Event] +# ## +# # Periodic timer event for checking the result of interrupt transfer execution. +# # +# EVENT_TYPE_PERIODIC_TIMER ## PRODUCES +# diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciQueue.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciQueue.c new file mode 100644 index 000000000..f25da6c41 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciQueue.c @@ -0,0 +1,993 @@ +/** @file + + The OHCI register operation routines. + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ohci.h" + + +/** + Map address of request structure buffer. + + @param Ohc The OHCI device. + @param Request The user request buffer. + @param MappedAddr Mapped address of request. + @param Map Identificaion of this mapping to return. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail to map the user request. + +**/ +EFI_STATUS +OhciMapUserRequest ( + IN USB_HC_DEV *Ohc, + IN OUT VOID *Request, + OUT UINT8 **MappedAddr, + OUT VOID **Map + ) +{ + EFI_STATUS Status; + UINTN Len; + EFI_PHYSICAL_ADDRESS PhyAddr; + +#if 1 + Len = sizeof (EFI_USB_DEVICE_REQUEST); + Status = Ohc->PciIo->Map ( + Ohc->PciIo, + EfiPciIoOperationBusMasterWrite, + Request, + &Len, + &PhyAddr, + Map + ); + + if (!EFI_ERROR (Status)) { + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + } +#else + Len = sizeof (EFI_USB_DEVICE_REQUEST); + Status = Ohc->PciIo->Map ( + Ohc->PciIo, + EfiPciIoOperationBusMasterRead, + Request, + &Len, + &PhyAddr, + Map + ); + + if (!EFI_ERROR (Status)) { + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + } +#endif + return Status; +} + + +/** + Map address of user data buffer. + + @param Ohc The OHCI device. + @param Direction Direction of the data transfer. + @param Data The user data buffer. + @param Len Length of the user data. + @param PktId Packet identificaion. + @param MappedAddr Mapped address to return. + @param Map Identificaion of this mapping to return. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail to map the user data. + +**/ +EFI_STATUS +OhciMapUserData ( + IN USB_HC_DEV *Ohc, + IN EFI_USB_DATA_DIRECTION Direction, + IN VOID *Data, + IN OUT UINTN *Len, + OUT UINT8 *PktId, + OUT UINT8 **MappedAddr, + OUT VOID **Map + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhyAddr; + + Status = EFI_SUCCESS; +#if 1 + switch (Direction) { + case EfiUsbDataIn: + // + // BusMasterWrite means cpu read + // + *PktId = INPUT_PACKET_ID; + Status = Ohc->PciIo->Map ( + Ohc->PciIo, + EfiPciIoOperationBusMasterRead, + Data, + Len, + &PhyAddr, + Map + ); + + if (EFI_ERROR (Status)) { + goto EXIT; + } + DEBUG((EFI_D_INIT, "Read Mapped : %p\n", *Map)); + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + break; + + case EfiUsbDataOut: + *PktId = OUTPUT_PACKET_ID; + Status = Ohc->PciIo->Map ( + Ohc->PciIo, + EfiPciIoOperationBusMasterWrite, + Data, + Len, + &PhyAddr, + Map + ); + + if (EFI_ERROR (Status)) { + goto EXIT; + } + DEBUG((EFI_D_INIT, "Write Mapped : %p\n", *Map)); + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + break; + + case EfiUsbNoData: + if ((Len != NULL) && (*Len != 0)) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + DEBUG((EFI_D_INIT, "No Mapped : %p\n", *Map)); + *PktId = OUTPUT_PACKET_ID; + *MappedAddr = NULL; + *Map = NULL; + break; + + default: + Status = EFI_INVALID_PARAMETER; + } +#else + switch (Direction) { + case EfiUsbDataIn: + // + // BusMasterWrite means cpu read + // + *PktId = INPUT_PACKET_ID; + Status = Ohc->PciIo->Map ( + Ohc->PciIo, + EfiPciIoOperationBusMasterWrite, + Data, + Len, + &PhyAddr, + Map + ); + + if (EFI_ERROR (Status)) { + goto EXIT; + } + + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + break; + + case EfiUsbDataOut: + *PktId = OUTPUT_PACKET_ID; + Status = Ohc->PciIo->Map ( + Ohc->PciIo, + EfiPciIoOperationBusMasterRead, + Data, + Len, + &PhyAddr, + Map + ); + + if (EFI_ERROR (Status)) { + goto EXIT; + } + + *MappedAddr = (UINT8 *) (UINTN) PhyAddr; + break; + + case EfiUsbNoData: + if ((Len != NULL) && (*Len != 0)) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + *PktId = OUTPUT_PACKET_ID; + *MappedAddr = NULL; + *Map = NULL; + break; + + default: + Status = EFI_INVALID_PARAMETER; + } +#endif +EXIT: + return Status; +} + + +/** + Link the TD To QH. + + @param Ohc The OHCI device. + @param Qh The queue head for the TD to link to. + @param Td The TD to link. + +**/ +VOID +OhciLinkTdToQh ( + IN USB_HC_DEV *Ohc, + IN OHCI_ED_HW *Ed, + IN UINT8 Class + ) +{ +#if 1 + UINT32 cmd; + + if(Class == HC_CLASS_CONTROL) //Controll + { + /* + cmd = OhciReadReg(Ohc, HC_CONTROL_OFFSET); + cmd &= ~(1<<5); + OhciWriteReg(Ohc, HC_CONTROL_OFFSET, cmd); */ + + cmd = OhciReadReg(Ohc, HC_COM_STATUS_OFFSET); + cmd |= (1<<1); + OhciWriteReg(Ohc, HC_COM_STATUS_OFFSET, cmd); + + OhciWriteReg(Ohc, HC_CTRL_HEADED_OFFSET, Ed); + + cmd = OhciReadReg(Ohc, HC_CONTROL_OFFSET); + cmd |= (1<<4); + OhciWriteReg(Ohc, HC_CONTROL_OFFSET, cmd); + } + else//Interrupt + {/* + cmd = OhciReadReg(Ohc, HC_CONTROL_OFFSET); + cmd &= ~(1<<4); + OhciWriteReg(Ohc, HC_CONTROL_OFFSET, cmd); + */ + cmd = OhciReadReg(Ohc, HC_COM_STATUS_OFFSET); + cmd |= (1<<2); + OhciWriteReg(Ohc, HC_COM_STATUS_OFFSET, cmd); + + OhciWriteReg(Ohc, HC_BULK_HEADED_OFFSET, Ed); + + cmd = OhciReadReg(Ohc, HC_CONTROL_OFFSET); + cmd |= (1<<5); + OhciWriteReg(Ohc, HC_CONTROL_OFFSET, cmd); + } +#else + EFI_PHYSICAL_ADDRESS PhyAddr; + + PhyAddr = UsbHcGetPciAddressForHostMem (Ohc->MemPool, Td, sizeof (OHCI_TD_HW)); + + ASSERT ((Qh != NULL) && (Td != NULL)); + + Qh->QhHw.VerticalLink = QH_VLINK (PhyAddr, FALSE); + Qh->TDs = (VOID *) Td; +#endif +} + + +/** + Unlink TD from the QH. + + @param Qh The queue head to unlink from. + @param Td The TD to unlink. + +**/ +VOID +OhciUnlinkTdFromQh ( + IN OHCI_QH_SW *Qh, + IN OHCI_TD_HW *Td + ) +{ +#if 1 +#else + ASSERT ((Qh != NULL) && (Td != NULL)); + + Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE); + Qh->TDs = NULL; +#endif +} + + +/** + Append a new TD To the previous TD. + + @param Ohc The OHCI device. + @param PrevTd Previous OHCI_TD_HW to be linked to. + @param ThisTd TD to link. + +**/ +VOID +OhciAppendTd ( + IN USB_HC_DEV *Ohc, + IN OHCI_TD_HW *PrevTd, + IN OHCI_TD_HW *ThisTd + ) +{ + EFI_PHYSICAL_ADDRESS PhyAddr; + + //PhyAddr = UsbHcGetPciAddressForHostMem (Ohc->MemPool, ThisTd, sizeof (OHCI_TD_HW)); + + ASSERT ((PrevTd != NULL) && (ThisTd != NULL)); + +#if 1 + PrevTd->next_td = (VOID *) ThisTd; +#else + PrevTd->TdHw.NextLink = TD_LINK (PhyAddr, TRUE, FALSE); + PrevTd->NextTd = (VOID *) ThisTd; +#endif +} + + +/** + Delete a list of TDs. + + @param Ohc The OHCI device. + @param FirstTd TD link list head. + + @return None. + +**/ +VOID +OhciDestoryTds ( + IN USB_HC_DEV *Ohc, + IN OHCI_TD_SW *FirstTd + ) +{ + OHCI_TD_SW *NextTd; + OHCI_TD_SW *ThisTd; + + DEBUG((EFI_D_INIT, "+++OhciDestoryTds()\n")); + + NextTd = FirstTd; + + while (NextTd != NULL) { + ThisTd = NextTd; + NextTd = ThisTd->NextTd; + if(ThisTd->TdHw) + { + DEBUG((EFI_D_INIT, "Destroy TDHW : %p\n", ThisTd->TdHw)); + UsbHcFreeMem (Ohc->MemPool, ThisTd->TdHw, sizeof (OHCI_TD_HW)); + } + DEBUG((EFI_D_INIT, "Destroy THSW : %p\n", ThisTd)); + UsbHcFreeMem (Ohc->MemPool, ThisTd, sizeof (OHCI_TD_SW)); + } + + DEBUG((EFI_D_INIT, "---OhciDestoryTds()\n")); +} + + +/** + Create an initialize a new queue head. + + @param Ohc The OHCI device. + @param Interval The polling interval for the queue. + + @return The newly created queue header. + +**/ +OHCI_QH_SW * +OhciCreateQh ( + IN USB_HC_DEV *Ohc, + IN UINTN Interval + ) +{ + OHCI_QH_SW *Qh; +#if 1 +#else + Qh = UsbHcAllocateMem (Ohc->MemPool, sizeof (OHCI_QH_SW)); + + if (Qh == NULL) { + return NULL; + } + + Qh->QhHw.HorizonLink = QH_HLINK (NULL, TRUE); + Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE); + Qh->Interval = OhciConvertPollRate(Interval); + Qh->TDs = NULL; + Qh->NextQh = NULL; +#endif + return Qh; +} + + +/** + Create and intialize a TD. + + @param Ohc The OHCI device. + + @return The newly allocated and initialized TD. + +**/ +OHCI_TD_HW * +OhciCreateTd ( + IN USB_HC_DEV *Ohc + ) +{ + OHCI_TD_HW *Td; + + Td = UsbHcAllocateMem (Ohc->MemPool, sizeof (OHCI_TD_HW)); + if (Td == NULL) { + return NULL; + } + + Td->current_buf_ptr = NULL; + Td->next_td = NULL; + Td->buffer_end = NULL; + + return Td; +} + + +/** + Create and initialize a TD for Setup Stage of a control transfer. + + @param Ohc The OHCI device. + @param DevAddr Device address. + @param Request A pointer to cpu memory address of Device request. + @param RequestPhy A pointer to pci memory address of Device request. + @param IsLow Full speed or low speed. + + @return The created setup Td Pointer. + +**/ +OHCI_TD_HW * +OhciCreateSetupTd ( + IN USB_HC_DEV *Ohc, + IN UINT8 DevAddr, + IN UINT8 *Request, + IN UINT8 *RequestPhy, + IN BOOLEAN IsLow + ) +{ + OHCI_TD_HW *Td; + + Td = OhciCreateTd (Ohc); + + if (Td == NULL) { + return NULL; + } +#if 1 + OhcDumpRequest(RequestPhy); + DEBUG((EFI_D_INIT, "LowSpeed : %d\n", IsLow)); + + Td->gtd_info.data = 0; + Td->gtd_info.b.buffer_rounding = 0; + Td->gtd_info.b.pid = SETUP_PACKET_ID; + Td->gtd_info.b.data_toggle = 2; // DATA0 + Td->current_buf_ptr = (UINT32)RequestPhy; + Td->next_td = NULL; + Td->buffer_end = (UINT32)RequestPhy + sizeof (EFI_USB_DEVICE_REQUEST)-1; +#else + Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE); + Td->TdHw.ShortPacket = FALSE; + Td->TdHw.IsIsoch = FALSE; + Td->TdHw.IntOnCpl = FALSE; + Td->TdHw.ErrorCount = 0x03; + Td->TdHw.Status |= USBTD_ACTIVE; + Td->TdHw.DataToggle = 0; + Td->TdHw.EndPoint = 0; + Td->TdHw.LowSpeed = IsLow ? 1 : 0; + Td->TdHw.DeviceAddr = DevAddr & 0x7F; + Td->TdHw.MaxPacketLen = (UINT32) (sizeof (EFI_USB_DEVICE_REQUEST) - 1); + Td->TdHw.PidCode = SETUP_PACKET_ID; + Td->TdHw.DataBuffer = (UINT32) (UINTN) RequestPhy; + + Td->Data = Request; + Td->DataLen = (UINT16) sizeof (EFI_USB_DEVICE_REQUEST); +#endif + return Td; +} + + +/** + Create a TD for data. + + @param Ohc The OHCI device. + @param DevAddr Device address. + @param Endpoint Endpoint number. + @param DataPtr A pointer to cpu memory address of Data buffer. + @param DataPhyPtr A pointer to pci memory address of Data buffer. + @param Len Data length. + @param PktId Packet ID. + @param Toggle Data toggle value. + @param IsLow Full speed or low speed. + + @return Data Td pointer if success, otherwise NULL. + +**/ +OHCI_TD_HW * +OhciCreateDataTd ( + IN USB_HC_DEV *Ohc, + IN UINT8 DevAddr, + IN UINT8 Endpoint, + IN UINT8 *DataPtr, + IN UINT8 *DataPhyPtr, + IN UINTN Len, + IN UINT8 PktId, + IN UINT8 Toggle, + IN BOOLEAN IsLow + ) +{ + OHCI_TD_HW *Td; + + //DEBUG((EFI_D_INIT, "+++OhciCreateDataTd(Len : %d)\n", Len)); + + // + // Code as length - 1, and the max valid length is 0x500 + // + ASSERT (Len <= 0x500); + + Td = OhciCreateTd (Ohc); + + if (Td == NULL) { + return NULL; + } + +#if 1 + Td->gtd_info.data = 0; + Td->gtd_info.b.buffer_rounding = 1; // may be smaller than the defined buffer + Td->gtd_info.b.pid = PktId; + Td->gtd_info.b.data_toggle = Toggle; // DATA1 + Td->current_buf_ptr = (UINT32) (UINTN) DataPhyPtr; + Td->next_td = NULL; + Td->buffer_end = (UINT32) (UINTN) DataPhyPtr + Len-1; +#else + Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE); + Td->TdHw.ShortPacket = FALSE; + Td->TdHw.IsIsoch = FALSE; + Td->TdHw.IntOnCpl = FALSE; + Td->TdHw.ErrorCount = 0x03; + Td->TdHw.Status = USBTD_ACTIVE; + Td->TdHw.LowSpeed = IsLow ? 1 : 0; + Td->TdHw.DataToggle = Toggle & 0x01; + Td->TdHw.EndPoint = Endpoint & 0x0F; + Td->TdHw.DeviceAddr = DevAddr & 0x7F; + Td->TdHw.MaxPacketLen = (UINT32) (Len - 1); + Td->TdHw.PidCode = (UINT8) PktId; + Td->TdHw.DataBuffer = (UINT32) (UINTN) DataPhyPtr; + + Td->Data = DataPtr; + Td->DataLen = (UINT16) Len; +#endif + + //DEBUG((EFI_D_INIT, "---OhciCreateDataTd()\n")); + + return Td; +} + + +/** + Create TD for the Status Stage of control transfer. + + @param Ohc The OHCI device. + @param DevAddr Device address. + @param PktId Packet ID. + @param IsLow Full speed or low speed. + + @return Status Td Pointer. + +**/ +OHCI_TD_HW * +OhciCreateStatusTd ( + IN USB_HC_DEV *Ohc, + IN UINT8 DevAddr, + IN UINT8 PktId, + IN BOOLEAN IsLow + ) +{ + OHCI_TD_HW *Td; + + Td = OhciCreateTd (Ohc); + + if (Td == NULL) { + return NULL; + } + +#if 1 + Td->gtd_info.data = 0; + Td->gtd_info.b.buffer_rounding = 1; // may be smaller than the defined buffer + Td->gtd_info.b.pid = PktId; + Td->gtd_info.b.data_toggle = 3; // DATA1 + Td->current_buf_ptr = 0; + Td->next_td = 0; + Td->buffer_end = 0; +#else + Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE); + Td->TdHw.ShortPacket = FALSE; + Td->TdHw.IsIsoch = FALSE; + Td->TdHw.IntOnCpl = FALSE; + Td->TdHw.ErrorCount = 0x03; + Td->TdHw.Status |= USBTD_ACTIVE; + Td->TdHw.MaxPacketLen = 0x7FF; //0x7FF: there is no data (refer to OHCI spec) + Td->TdHw.DataToggle = 1; + Td->TdHw.EndPoint = 0; + Td->TdHw.LowSpeed = IsLow ? 1 : 0; + Td->TdHw.DeviceAddr = DevAddr & 0x7F; + Td->TdHw.PidCode = (UINT8) PktId; + Td->TdHw.DataBuffer = (UINT32) (UINTN) NULL; + + Td->Data = NULL; + Td->DataLen = 0; +#endif + return Td; +} + +OHCI_ED_HW * +OhciCreateEd ( + IN USB_HC_DEV *Ohc, + IN UINT8 DeviceAddr, + IN UINT32 *QH, + IN UINT8 MaxPacket, + IN BOOLEAN IsLow + ) +{ + OHCI_ED_HW *Ed; + + Ed = UsbHcAllocateMem (Ohc->MemPool, sizeof (OHCI_ED_HW)); + if (Ed == NULL) { + return NULL; + } + + Ed->ed_info.data = 0; + Ed->ed_info.b.func_addr = DeviceAddr; + Ed->ed_info.b.ep_num = 0; + Ed->ed_info.b.direction = 0; + Ed->ed_info.b.speed = IsLow?1:0; // speed + Ed->ed_info.b.format = 0; // gTD + Ed->ed_info.b.mps = MaxPacket; + Ed->tail_td_ptr = 0; + Ed->head_td_ptr = QH; + Ed->next_ed = 0; + + return Ed; +} + +/** + Create Tds list for Control Transfer. + + @param Ohc The OHCI device. + @param DeviceAddr The device address. + @param DataPktId Packet Identification of Data Tds. + @param Request A pointer to cpu memory address of request structure buffer to transfer. + @param RequestPhy A pointer to pci memory address of request structure buffer to transfer. + @param Data A pointer to cpu memory address of user data buffer to transfer. + @param DataPhy A pointer to pci memory address of user data buffer to transfer. + @param DataLen Length of user data to transfer. + @param MaxPacket Maximum packet size for control transfer. + @param IsLow Full speed or low speed. + + @return The Td list head for the control transfer. + +**/ +OHCI_ED_HW * +OhciCreateCtrlTds ( + IN USB_HC_DEV *Ohc, + IN UINT8 DeviceAddr, + IN UINT8 DataPktId, + IN UINT8 *Request, + IN UINT8 *RequestPhy, + IN UINT8 *Data, + IN UINT8 *DataPhy, + IN UINTN DataLen, + IN UINT8 MaxPacket, + IN BOOLEAN IsLow + ) +{ + OHCI_ED_HW *Ed; + OHCI_TD_HW *SetupTd; + OHCI_TD_HW *FirstDataTd; + OHCI_TD_HW *DataTd; + OHCI_TD_HW *PrevDataTd; + OHCI_TD_HW *StatusTd; + UINT8 DataToggle; + UINT8 StatusPktId; + UINTN ThisTdLen; + + + DataTd = NULL; + SetupTd = NULL; + FirstDataTd = NULL; + PrevDataTd = NULL; + StatusTd = NULL; + + // + // Create setup packets for the transfer + // + SetupTd = OhciCreateSetupTd (Ohc, DeviceAddr, Request, RequestPhy, IsLow); + + if (SetupTd == NULL) { + return NULL; + } + + // + // Create data packets for the transfer + // + DataToggle = 1; + DEBUG((EFI_D_INIT, "Max Len %d, Dat Len ; %d\n", MaxPacket, DataLen)); + while (DataLen > 0) { + // + // PktSize is the data load size in each Td. + // + ThisTdLen = (DataLen > MaxPacket ? MaxPacket : DataLen); + + DataTd = OhciCreateDataTd ( + Ohc, + DeviceAddr, + 0, + Data, //cpu memory address + DataPhy, //Pci memory address + ThisTdLen, + DataPktId, + (DataToggle + 2), + IsLow + ); + + if (DataTd == NULL) { + goto FREE_TD; + } + + if (FirstDataTd == NULL) { + FirstDataTd = DataTd; + FirstDataTd->next_td = NULL; + } else { + OhciAppendTd (Ohc, PrevDataTd, DataTd); + } + + DataToggle ^= 1; + PrevDataTd = DataTd; + Data += ThisTdLen; + DataPhy += ThisTdLen; + DataLen -= ThisTdLen; + } + + // + // Status packet is on the opposite direction to data packets + // + if (OUTPUT_PACKET_ID == DataPktId) { + StatusPktId = INPUT_PACKET_ID; + } else { + StatusPktId = OUTPUT_PACKET_ID; + } + + StatusTd = OhciCreateStatusTd (Ohc, DeviceAddr, StatusPktId, IsLow); + + if (StatusTd == NULL) { + DEBUG((EFI_D_ERROR, "FAIL! OhciCreateStatusTd\n")); + goto FREE_TD; + } + + // + // Link setup Td -> data Tds -> status Td together + // + if (FirstDataTd != NULL) { + OhciAppendTd (Ohc, SetupTd, FirstDataTd); + OhciAppendTd (Ohc, PrevDataTd, StatusTd); + } else { + OhciAppendTd (Ohc, SetupTd, StatusTd); + } + + //iky + + Ed = Ohc->EdHw[0]; + Ed->ed_info.data = 0; + Ed->ed_info.b.func_addr = DeviceAddr; + Ed->ed_info.b.ep_num = 0; + Ed->ed_info.b.direction = 0; + Ed->ed_info.b.speed = IsLow?1:0; // speed + Ed->ed_info.b.format = 0; // gTD + Ed->ed_info.b.mps = MaxPacket; + Ed->tail_td_ptr = 0; + Ed->head_td_ptr = SetupTd; + Ed->next_ed = 0; + + Ohc->LastTd = StatusTd; + + return Ed; + +FREE_TD: + if (SetupTd != NULL) { + OhciDestoryTds (Ohc, SetupTd); + } + + if (FirstDataTd != NULL) { + OhciDestoryTds (Ohc, FirstDataTd); + } + + return NULL; +} + + +/** + Create Tds list for Bulk/Interrupt Transfer. + + @param Ohc USB_HC_DEV. + @param DevAddr Address of Device. + @param EndPoint Endpoint Number. + @param PktId Packet Identification of Data Tds. + @param Data A pointer to cpu memory address of user data buffer to transfer. + @param DataPhy A pointer to pci memory address of user data buffer to transfer. + @param DataLen Length of user data to transfer. + @param DataToggle Data Toggle Pointer. + @param MaxPacket Maximum packet size for Bulk/Interrupt transfer. + @param IsLow Is Low Speed Device. + + @return The Tds list head for the bulk transfer. + +**/ +OHCI_TD_HW * +OhciCreateBulkOrIntTds ( + IN USB_HC_DEV *Ohc, + IN UINT8 DevAddr, + IN UINT8 EndPoint, + IN UINT8 PktId, + IN UINT8 *Data, + IN UINT8 *DataPhy, + IN UINTN DataLen, + IN OUT UINT8 *DataToggle, + IN UINT8 MaxPacket, + IN BOOLEAN IsLow + ) +{ + OHCI_ED_HW *Ed; + OHCI_TD_HW *DataTd; + OHCI_TD_HW *FirstDataTd; + OHCI_TD_HW *PrevDataTd; + UINTN ThisTdLen; + UINT8 EP; +#if 1 + EP = EndPoint >> 7; + DEBUG((EFI_D_INIT, "+++OhciCreateBulkOrIntTds(EP%d : %p)\n", EP, Ohc->EdHw[EP])); + + DataTd = NULL; + FirstDataTd = NULL; + PrevDataTd = NULL; + // + // Create data packets for the transfer + // + while (DataLen > 0) { + // + // PktSize is the data load size that each Td. + // + ThisTdLen = DataLen; + + if (DataLen > MaxPacket) { + ThisTdLen = MaxPacket; + } + + DataTd = OhciCreateDataTd ( + Ohc, + DevAddr, + EndPoint, + Data, + DataPhy, + ThisTdLen, + PktId, + (*DataToggle + 2), + IsLow + ); + + if (DataTd == NULL) { + DEBUG((EFI_D_ERROR, "FAIL! OhciCreateDataTd\n")); + goto FREE_TD; + } +/* + if (PktId == INPUT_PACKET_ID) { + DataTd->gtd_info.b.buffer_rounding = 1; + } +*/ + if (FirstDataTd == NULL) { + FirstDataTd = DataTd; + FirstDataTd->next_td = NULL; + } else { + OhciAppendTd (Ohc, PrevDataTd, DataTd); + } + + *DataToggle ^= 1; + PrevDataTd = DataTd; + Data += ThisTdLen; + DataPhy += ThisTdLen; + DataLen -= ThisTdLen; + } + + Ed = Ohc->EdHw[EP]; + Ed->ed_info.data = 0; + Ed->ed_info.b.func_addr = DevAddr; + Ed->ed_info.b.ep_num = EP; + Ed->ed_info.b.direction = 0; //IN DIRECTION + Ed->ed_info.b.speed = IsLow?1:0; // speed + Ed->ed_info.b.format = 0; // gTD + Ed->ed_info.b.mps = MaxPacket; + Ed->tail_td_ptr = 0; + Ed->head_td_ptr = FirstDataTd; + Ed->next_ed = 0; + + Ohc->LastTd = PrevDataTd; + + DEBUG((EFI_D_INIT, "---OhciCreateBulkOrIntTds()\n")); + + return Ed; + +FREE_TD: + if (FirstDataTd != NULL) { + OhciDestoryTds (Ohc, FirstDataTd); + } + + return NULL; +#else + DataTd = NULL; + FirstDataTd = NULL; + PrevDataTd = NULL; + + // + // Create data packets for the transfer + // + while (DataLen > 0) { + // + // PktSize is the data load size that each Td. + // + ThisTdLen = DataLen; + + if (DataLen > MaxPacket) { + ThisTdLen = MaxPacket; + } + + DataTd = OhciCreateDataTd ( + Ohc, + DevAddr, + EndPoint, + Data, + DataPhy, + ThisTdLen, + PktId, + *DataToggle, + IsLow + ); + + if (DataTd == NULL) { + goto FREE_TD; + } + + if (PktId == INPUT_PACKET_ID) { + DataTd->TdHw.ShortPacket = TRUE; + } + + if (FirstDataTd == NULL) { + FirstDataTd = DataTd; + FirstDataTd->NextTd = NULL; + } else { + OhciAppendTd (Ohc, PrevDataTd, DataTd); + } + + *DataToggle ^= 1; + PrevDataTd = DataTd; + Data += ThisTdLen; + DataPhy += ThisTdLen; + DataLen -= ThisTdLen; + } + + return FirstDataTd; + +FREE_TD: + if (FirstDataTd != NULL) { + OhciDestoryTds (Ohc, FirstDataTd); + } +#endif +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciQueue.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciQueue.h new file mode 100644 index 000000000..8c22c95e6 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciQueue.h @@ -0,0 +1,395 @@ +/** @file + + The definition for OHCI register operation routines. + +Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_OHCI_QUEUE_H_ +#define _EFI_OHCI_QUEUE_H_ + +#if 1 +//================================================================== +// data structure +// +// <OHCI> +// + +typedef union +{ + UINT32 data; + struct { + // bit[6:0] : function address + unsigned func_addr : 7; + // bit[10:7] : endpoint number + unsigned ep_num : 4; + // bit[12:11] : direction + unsigned direction : 2; + // bit[13] : speed + unsigned speed : 1; + // bit[14] : skip (1->skip this ED) + unsigned skip : 1; + // bit[15] : format (0->gTD, 1->isoTD) + unsigned format : 1; + // bit[26:16] : maximum packet size + unsigned mps : 11; + // bit[31:27] : + unsigned reserved31_27 : 5; + }b; +}ed_info_t; + +typedef struct +{ + ed_info_t ed_info; + UINT32 tail_td_ptr; + UINT32 head_td_ptr; + UINT32 next_ed; +} OHCI_ED_HW; + +typedef union +{ + UINT32 data; + struct { + // bit[17:0] : + unsigned reserved17_0 : 18; + // bit[18] : buffer rounding (0->exactly fill the defined buffer, 1->may be smaller than the defined buffer) + unsigned buffer_rounding : 1; + // bit[20:19] : pid (0->setup, 1->out, 2->in, 3->reserved) + unsigned pid : 2; + // bit[23:21] : delay interrupt + unsigned delay_interrupt : 3; + // bit[25:24] : data toggle + unsigned data_toggle : 2; + // bit[27:26] : error count + unsigned error_count : 2; + // bit[31:28] : condition code + unsigned condition_code : 4; + }b; +}gtd_info_t; + +typedef struct +{ + gtd_info_t gtd_info; + UINT32 current_buf_ptr; + UINT32 next_td; + UINT32 buffer_end; +} OHCI_TD_HW; + +typedef struct _OHCI_TD_SW OHCI_TD_SW; + +struct _OHCI_TD_SW{ + OHCI_TD_HW *TdHw; + OHCI_TD_SW *NextTd; + UINT32 *Data; + UINT32 DataLen; +}; + +struct _OHCI_HCCA { +#define NUM_INTS 32 + UINT32 int_table [NUM_INTS]; /* periodic schedule */ + + /* + * OHCI defines u16 frame_no, followed by u16 zero pad. + * Since some processors can't do 16 bit bus accesses, + * portable access must be a 32 bits wide. + */ + UINT32 frame_no; /* current frame number */ + UINT32 done_head; /* info returned for an interrupt */ + UINT8 reserved_for_hc [116]; + UINT8 what [4]; /* spec only identifies 252 bytes :) */ +} __attribute__ ((aligned(256))); + +typedef struct _OHCI_HCCA OHCI_HCCA; + + + + + + + + + + + + + + + + + + +typedef struct { + UINT32 HorizonLink; + UINT32 VerticalLink; +} OHCI_QH_HW; + +typedef struct _OHCI_QH_SW OHCI_QH_SW; + +struct _OHCI_QH_SW { + OHCI_QH_HW QhHw; + OHCI_QH_SW *NextQh; + OHCI_TD_HW *TDs; + UINTN Interval; +}; +#else +// +// Macroes used to set various links in OHCI's driver. +// In this OHCI driver, QH's horizontal link always pointers to other QH, +// and its vertical link always pointers to TD. TD's next pointer always +// pointers to other sibling TD. Frame link always pointers to QH because +// ISO transfer isn't supported. +// +// We should use UINT32 to access these pointers to void race conditions +// with hardware. +// +#define QH_HLINK(Pointer, Terminate) \ + (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | 0x02 | ((Terminate) ? 0x01 : 0)) + +#define QH_VLINK(Pointer, Terminate) \ + (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | ((Terminate) ? 0x01 : 0)) + +#define TD_LINK(Pointer, VertFirst, Terminate) \ + (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | \ + ((VertFirst) ? 0x04 : 0) | ((Terminate) ? 0x01 : 0)) + +#define LINK_TERMINATED(Link) (((Link) & 0x01) != 0) + +#define OHCI_ADDR(QhOrTd) ((VOID *) (UINTN) ((QhOrTd) & 0xFFFFFFF0)) + +#pragma pack(1) +// +// Both links in QH has this internal structure: +// Next pointer: 28, Reserved: 2, NextIsQh: 1, Terminate: 1 +// This is the same as frame list entry. +// +typedef struct { + UINT32 HorizonLink; + UINT32 VerticalLink; +} OHCI_QH_HW; + +// +// Next link in TD has this internal structure: +// Next pointer: 28, Reserved: 1, Vertical First: 1, NextIsQh: 1, Terminate: 1 +// +typedef struct { + UINT32 NextLink; + UINT32 ActualLen : 11; + UINT32 Reserved1 : 5; + UINT32 Status : 8; + UINT32 IntOnCpl : 1; + UINT32 IsIsoch : 1; + UINT32 LowSpeed : 1; + UINT32 ErrorCount : 2; + UINT32 ShortPacket : 1; + UINT32 Reserved2 : 2; + UINT32 PidCode : 8; + UINT32 DeviceAddr : 7; + UINT32 EndPoint : 4; + UINT32 DataToggle : 1; + UINT32 Reserved3 : 1; + UINT32 MaxPacketLen: 11; + UINT32 DataBuffer; +} OHCI_TD_HW; +#pragma pack() + +typedef struct _OHCI_TD_SW OHCI_TD_SW; +typedef struct _OHCI_QH_SW OHCI_QH_SW; + +struct _OHCI_QH_SW { + OHCI_QH_HW QhHw; + OHCI_QH_SW *NextQh; + OHCI_TD_SW *TDs; + UINTN Interval; +}; + +struct _OHCI_TD_SW { + OHCI_TD_HW TdHw; + OHCI_TD_SW *NextTd; + UINT8 *Data; + UINT16 DataLen; +}; +#endif + +/** + Link the TD To QH. + + @param Ohc The OHCI device. + @param Qh The queue head for the TD to link to. + @param Td The TD to link. + +**/ +VOID +OhciLinkTdToQh ( + IN USB_HC_DEV *Ohc, + IN OHCI_ED_HW *Ed, + IN UINT8 Class + ); + + +/** + Unlink TD from the QH. + + @param Qh The queue head to unlink from. + @param Td The TD to unlink. + + @return None. + +**/ +VOID +OhciUnlinkTdFromQh ( + IN OHCI_QH_SW *Qh, + IN OHCI_TD_HW *Td + ); + +/** + Map address of request structure buffer. + + @param Ohc The OHCI device. + @param Request The user request buffer. + @param MappedAddr Mapped address of request. + @param Map Identificaion of this mapping to return. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail to map the user request. + +**/ +EFI_STATUS +OhciMapUserRequest ( + IN USB_HC_DEV *Ohc, + IN OUT VOID *Request, + OUT UINT8 **MappedAddr, + OUT VOID **Map + ); + + +/** + Map address of user data buffer. + + @param Ohc The OHCI device. + @param Direction Direction of the data transfer. + @param Data The user data buffer. + @param Len Length of the user data. + @param PktId Packet identificaion. + @param MappedAddr Mapped address to return. + @param Map Identificaion of this mapping to return. + + @return EFI_SUCCESS Success. + @return EFI_DEVICE_ERROR Fail to map the user data. + +**/ +EFI_STATUS +OhciMapUserData ( + IN USB_HC_DEV *Ohc, + IN EFI_USB_DATA_DIRECTION Direction, + IN VOID *Data, + IN OUT UINTN *Len, + OUT UINT8 *PktId, + OUT UINT8 **MappedAddr, + OUT VOID **Map + ); + + +/** + Delete a list of TDs. + + @param Ohc The OHCI device. + @param FirstTd TD link list head. + + @return None. + +**/ +VOID +OhciDestoryTds ( + IN USB_HC_DEV *Ohc, + IN OHCI_TD_SW *FirstTd + ); + + +/** + Create an initialize a new queue head. + + @param Ohc The OHCI device. + @param Interval The polling interval for the queue. + + @return The newly created queue header. + +**/ +OHCI_QH_SW * +OhciCreateQh ( + IN USB_HC_DEV *Ohc, + IN UINTN Interval + ); + + +/** + Create Tds list for Control Transfer. + + @param Ohc The OHCI device. + @param DeviceAddr The device address. + @param DataPktId Packet Identification of Data Tds. + @param Request A pointer to cpu memory address of request structure buffer to transfer. + @param RequestPhy A pointer to pci memory address of request structure buffer to transfer. + @param Data A pointer to cpu memory address of user data buffer to transfer. + @param DataPhy A pointer to pci memory address of user data buffer to transfer. + @param DataLen Length of user data to transfer. + @param MaxPacket Maximum packet size for control transfer. + @param IsLow Full speed or low speed. + + @return The Td list head for the control transfer. + +**/ +OHCI_ED_HW * +OhciCreateCtrlTds ( + IN USB_HC_DEV *Ohc, + IN UINT8 DeviceAddr, + IN UINT8 DataPktId, + IN UINT8 *Request, + IN UINT8 *RequestPhy, + IN UINT8 *Data, + IN UINT8 *DataPhy, + IN UINTN DataLen, + IN UINT8 MaxPacket, + IN BOOLEAN IsLow + ); + + +/** + Create Tds list for Bulk/Interrupt Transfer. + + @param Ohc USB_HC_DEV. + @param DevAddr Address of Device. + @param EndPoint Endpoint Number. + @param PktId Packet Identification of Data Tds. + @param Data A pointer to cpu memory address of user data buffer to transfer. + @param DataPhy A pointer to pci memory address of user data buffer to transfer. + @param DataLen Length of user data to transfer. + @param DataToggle Data Toggle Pointer. + @param MaxPacket Maximum packet size for Bulk/Interrupt transfer. + @param IsLow Is Low Speed Device. + + @return The Tds list head for the bulk transfer. + +**/ +OHCI_TD_HW * +OhciCreateBulkOrIntTds ( + IN USB_HC_DEV *Ohc, + IN UINT8 DevAddr, + IN UINT8 EndPoint, + IN UINT8 PktId, + IN UINT8 *Data, + IN UINT8 *DataPhy, + IN UINTN DataLen, + IN OUT UINT8 *DataToggle, + IN UINT8 MaxPacket, + IN BOOLEAN IsLow + ); + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciReg.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciReg.c new file mode 100644 index 000000000..29879027e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciReg.c @@ -0,0 +1,292 @@ +/** @file + + The OHCI register operation routines. + +Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ohci.h" + + +/** + Read a OHCI register. + + @param PciIo The EFI_PCI_IO_PROTOCOL to use. + @param Offset Register offset to USB_BAR_INDEX. + + @return Content of register. + +**/ +UINT32 +OhciReadReg ( + IN USB_HC_DEV *Ohc, + IN UINT32 Offset + ) +{ + UINT32 Data; + EFI_STATUS Status; + + Status = Ohc->PciIo->Mem.Read ( + Ohc->PciIo, + EfiPciIoWidthUint32, + OHC_BAR_INDEX, + (UINT64) (Offset), + 1, + &Data + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "OhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset)); + Data = 0xFFFF; + } + + return Data; +} + + +/** + Write data to OHCI register. + + @param PciIo The EFI_PCI_IO_PROTOCOL to use. + @param Offset Register offset to USB_BAR_INDEX. + @param Data Data to write. + +**/ +VOID +OhciWriteReg ( + IN USB_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + EFI_STATUS Status; + + Status = Ohc->PciIo->Mem.Write ( + Ohc->PciIo, + EfiPciIoWidthUint32, + OHC_BAR_INDEX, + (UINT64) (Offset), + 1, + &Data + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "OhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset)); + } +} + + +/** + Set a bit of the OHCI Register. + + @param PciIo The EFI_PCI_IO_PROTOCOL to use. + @param Offset Register offset to USB_BAR_INDEX. + @param Bit The bit to set. + +**/ +VOID +OhciSetRegBit ( + IN USB_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT16 Bit + ) +{ + UINT16 Data; + + Data = OhciReadReg (Ohc, Offset); + Data = (UINT16) (Data |Bit); + OhciWriteReg (Ohc, Offset, Data); +} + + +/** + Clear a bit of the OHCI Register. + + @param PciIo The PCI_IO protocol to access the PCI. + @param Offset Register offset to USB_BAR_INDEX. + @param Bit The bit to clear. + +**/ +VOID +OhciClearRegBit ( + IN USB_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT16 Bit + ) +{ + UINT16 Data; + + Data = OhciReadReg (Ohc, Offset); + Data = (UINT16) (Data & ~Bit); + OhciWriteReg (Ohc, Offset, Data); +} + + +/** + Clear all the interrutp status bits, these bits + are Write-Clean. + + @param Ohc The OHCI device. + +**/ +VOID +OhciAckAllInterrupt ( + IN USB_HC_DEV *Ohc + ) +{ + //OhciWriteReg (Ohc, USBSTS_OFFSET, 0x3F); + + // + // If current HC is halted, re-enable it. Host Controller Process Error + // is a temporary error status. + // + if (!OhciIsHcWorking (Ohc)) { + DEBUG ((EFI_D_ERROR, "OhciAckAllInterrupt: re-enable the OHCI from system error\n")); + Ohc->Usb2Hc.SetState (&Ohc->Usb2Hc, EfiUsbHcStateOperational); + } +} + + +/** + Stop the host controller. + + @param Ohc The OHCI device. + @param Timeout Max time allowed. + + @retval EFI_SUCCESS The host controller is stopped. + @retval EFI_TIMEOUT Failed to stop the host controller. + +**/ +EFI_STATUS +OhciStopHc ( + IN USB_HC_DEV *Ohc, + IN UINTN Timeout + ) +{ +#if 1 +/* + UINT32 UsbCtr; + UsbCtr = OhciReadReg(Ohc, HC_CONTROL_OFFSET); + UsbCtr &= (1<<9); //all except of RWC is clear + OhciWriteReg(Ohc, HC_CONTROL_OFFSET, UsbCtr); +*/ + return EFI_SUCCESS; +#else + UINT16 UsbSts; + UINTN Index; + OhciClearRegBit (Ohc, USBCMD_OFFSET, USBCMD_RS); + + // + // ensure the HC is in halt status after send the stop command + // Timeout is in us unit. + // + for (Index = 0; Index < (Timeout / 50) + 1; Index++) { + UsbSts = OhciReadReg (Ohc, USBSTS_OFFSET); + + if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) { + return EFI_SUCCESS; + } + + gBS->Stall (50); + } + + return EFI_TIMEOUT; +#endif +} + + +/** + Check whether the host controller operates well. + + @param PciIo The PCI_IO protocol to use. + + @retval TRUE Host controller is working. + @retval FALSE Host controller is halted or system error. + +**/ +BOOLEAN +OhciIsHcWorking ( + IN USB_HC_DEV *Ohc + ) +{ + UINT16 UsbSts; + /* + UsbSts = OhciReadReg (Ohc, USBSTS_OFFSET); + + if ((UsbSts & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) { + DEBUG ((EFI_D_ERROR, "OhciIsHcWorking: current USB state is %x\n", UsbSts)); + return FALSE; + } + */ + return TRUE; +} + + +/** + Set the OHCI frame list base address. It can't use + OhciWriteReg which access memory in UINT16. + + @param PciIo The EFI_PCI_IO_PROTOCOL to use. + @param Addr Address to set. + +**/ +/* +VOID +OhciSetFrameListBaseAddr ( + IN USB_HC_DEV *Ohc, + IN VOID *Addr + ) +{ + EFI_STATUS Status; + UINT32 Data; + + Data = (UINT32) ((UINTN) Addr & 0xFFFFF000); + + Status = PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint32, + USB_BAR_INDEX, + (UINT64) USB_FRAME_BASE_OFFSET, + 1, + &Data + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "OhciSetFrameListBaseAddr: PciIo Io.Write error: %r\n", Status)); + } +} +*/ + +/** + Disable USB Emulation. + + @param PciIo The EFI_PCI_IO_PROTOCOL protocol to use. + +**/ + +/* +VOID +OhciTurnOffUsbEmulation ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + UINT16 Command; + + Command = 0; + + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + USB_EMULATION_OFFSET, + 1, + &Command + ); +}*/ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciReg.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciReg.h new file mode 100644 index 000000000..729720e98 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciReg.h @@ -0,0 +1,286 @@ +/** @file + + The definition for OHCI register operation routines. + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_OHCI_REG_H_ +#define _EFI_OHCI_REG_H_ + +// +// OHCI register offset +// + +#define OHCI_FRAME_NUM 1024 + +// +// Register offset and PCI related staff +// +#define USB_BAR_INDEX 4 + +#define USBCMD_OFFSET 0 +#define USBSTS_OFFSET 2 +#define USBINTR_OFFSET 4 +//#define HC_PORT_STATUS_OFFSET 0x10 +#define USB_FRAME_NO_OFFSET 6 +#define USB_FRAME_BASE_OFFSET 8 +#define USB_EMULATION_OFFSET 0xC0 + +// Register offset for OHCI +#define INC4(a) ((a)+4) +#define HC_REVISION_OFFSET 0x0 +#define HC_CONTROL_OFFSET INC4(HC_REVISION_OFFSET) +#define HC_COM_STATUS_OFFSET INC4(HC_CONTROL_OFFSET) +#define HC_INT_STATUS_OFFSET INC4(HC_COM_STATUS_OFFSET) +#define HC_INT_ENABLE_OFFSET INC4(HC_INT_STATUS_OFFSET) +#define HC_INT_DISABLE_OFFSET INC4(HC_INT_ENABLE_OFFSET) +#define HC_HCCA_OFFSET INC4(HC_INT_DISABLE_OFFSET) +#define HC_PERIOD_CUTTENTED_OFFSET INC4(HC_HCCA_OFFSET) + + +#define HC_PRID_HEADED_OFFSET 0x40 +#define HC_PRID_CURRED_OFFSET 0x1C +#define HC_CTRL_HEADED_OFFSET 0x20 +#define HC_CTRL_CURRED_OFFSET 0x24 +#define HC_BULK_HEADED_OFFSET 0x28 +#define HC_BULK_CURRED_OFFSET 0x2C + +#define HC_FMINTERVAL_OFFSET 0x34 +#define HC_RH_DESCRIPTORA_OFFSET 0x48 +#define HC_RH_DESCRIPTORB_OFFSET 0x4C +#define HC_RH_STATUS_OFFSET 0x50 +#define HC_PORT_STATUS_OFFSET 0x54 + + +#define HC_CLASS_CONTROL 0 +#define HC_CLASS_INTERRUPT 1 + +// +// Packet IDs +// +#define SETUP_PACKET_ID 0x0 +#define OUTPUT_PACKET_ID 0x1 +#define INPUT_PACKET_ID 0x2 +#define ERROR_PACKET_ID 0x3 + +// +// USB port status and control bit definition. +// +#define USBPORTSC_CCS BIT0 // Current Connect Status +#define USBPORTSC_PED BIT1 // Port Enable / Disable +#define USBPORTSC_SUSP BIT2 // Suspend +#define USBPORTSC_POCI BIT3 // OVER CURRNET INDICATOR +#define USBPORTSC_PR BIT4 // Port Reset + +#define USBPORTSC_PPS BIT8 // Port Power +#define USBPORTSC_LSDA BIT9 // Low Speed Device Attached + +#define USBPORTSC_CSC BIT16 // Connect Status Change +#define USBPORTSC_PEDC BIT17 // Enable Change +#define USBPORTSC_PSSC BIT18 // Suspend Change +#define USBPORTSC_OCIC BIT19 // Over Currnet Change +#define USBPORTSC_PRSC BIT20 // Reset Change + + + + + +// +// OHCI Spec said it must implement 2 ports each host at least, +// and if more, check whether the bit7 of PORTSC is always 1. +// So here assume the max of port number each host is 16. +// +#define USB_MAX_ROOTHUB_PORT 0x0F + +// +// Command register bit definitions +// +#define USBCMD_RS BIT0 // Run/Stop +#define USBCMD_HCRESET BIT1 // Host reset +#define USBCMD_GRESET BIT2 // Global reset +#define USBCMD_EGSM BIT3 // Global Suspend Mode +#define USBCMD_FGR BIT4 // Force Global Resume +#define USBCMD_SWDBG BIT5 // SW Debug mode +#define USBCMD_CF BIT6 // Config Flag (sw only) +#define USBCMD_MAXP BIT7 // Max Packet (0 = 32, 1 = 64) + +// +// USB Status register bit definitions +// +#define USBSTS_USBINT BIT0 // Interrupt due to IOC +#define USBSTS_ERROR BIT1 // Interrupt due to error +#define USBSTS_RD BIT2 // Resume Detect +#define USBSTS_HSE BIT3 // Host System Error +#define USBSTS_HCPE BIT4 // Host Controller Process Error +#define USBSTS_HCH BIT5 // HC Halted + +#define USBTD_ACTIVE BIT7 // TD is still active +#define USBTD_STALLED BIT6 // TD is stalled +#define USBTD_BUFFERR BIT5 // Buffer underflow or overflow +#define USBTD_BABBLE BIT4 // Babble condition +#define USBTD_NAK BIT3 // NAK is received +#define USBTD_CRC BIT2 // CRC/Time out error +#define USBTD_BITSTUFF BIT1 // Bit stuff error + +#define OHC_BAR_INDEX 0 // how many bytes away from USB_BASE to 0x10 + +/** + Read a OHCI register. + + @param PciIo The EFI_PCI_IO_PROTOCOL to use. + @param Offset Register offset to USB_BAR_INDEX. + + @return Content of register. + +**/ +UINT32 +OhciReadReg ( + IN USB_HC_DEV *Ohc, + IN UINT32 Offset + ); + + + +/** + Write data to OHCI register. + + @param PciIo The EFI_PCI_IO_PROTOCOL to use. + @param Offset Register offset to USB_BAR_INDEX. + @param Data Data to write. + + @return None. + +**/ +VOID +OhciWriteReg ( + IN USB_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT32 Data + ); + + + +/** + Set a bit of the OHCI Register. + + @param PciIo The EFI_PCI_IO_PROTOCOL to use. + @param Offset Register offset to USB_BAR_INDEX. + @param Bit The bit to set. + + @return None. + +**/ +VOID +OhciSetRegBit ( + IN USB_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT16 Bit + ); + + + +/** + Clear a bit of the OHCI Register. + + @param PciIo The PCI_IO protocol to access the PCI. + @param Offset Register offset to USB_BAR_INDEX. + @param Bit The bit to clear. + + @return None. + +**/ +VOID +OhciClearRegBit ( + IN USB_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT16 Bit + ); + + +/** + Clear all the interrutp status bits, these bits + are Write-Clean. + + @param Ohc The OHCI device. + + @return None. + +**/ +VOID +OhciAckAllInterrupt ( + IN USB_HC_DEV *Ohc + ); + + +/** + Stop the host controller. + + @param Ohc The OHCI device. + @param Timeout Max time allowed. + + @retval EFI_SUCCESS The host controller is stopped. + @retval EFI_TIMEOUT Failed to stop the host controller. + +**/ +EFI_STATUS +OhciStopHc ( + IN USB_HC_DEV *Ohc, + IN UINTN Timeout + ); + + + +/** + Check whether the host controller operates well. + + @param PciIo The PCI_IO protocol to use. + + @retval TRUE Host controller is working. + @retval FALSE Host controller is halted or system error. + +**/ +BOOLEAN +OhciIsHcWorking ( + IN USB_HC_DEV *Ohc + ); + + +/** + Set the OHCI frame list base address. It can't use + OhciWriteReg which access memory in UINT16. + + @param PciIo The EFI_PCI_IO_PROTOCOL to use. + @param Addr Address to set. + + @return None. + +**/ +VOID +OhciSetFrameListBaseAddr ( + IN USB_HC_DEV *Ohc, + IN VOID *Addr + ); + + +/** + Disable USB Emulation. + + @param PciIo The EFI_PCI_IO_PROTOCOL protocol to use. + + @return None. + +**/ +VOID +OhciTurnOffUsbEmulation ( + IN USB_HC_DEV *Ohc + ); +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciSched.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciSched.c new file mode 100644 index 000000000..a8f99a3d4 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciSched.c @@ -0,0 +1,1254 @@ +/** @file + + The EHCI register operation routines. + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ohci.h" + + +/** + Create Frame List Structure. + + @param Ohc OHCI device. + + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. + @retval EFI_UNSUPPORTED Map memory fail. + @retval EFI_SUCCESS Success. + +**/ +EFI_STATUS +OhciInitFrameList ( + IN USB_HC_DEV *Ohc + ) +{ + EFI_PHYSICAL_ADDRESS MappedAddr; + EFI_STATUS Status; + VOID *Buffer; + VOID *Mapping; + UINTN Pages; + UINTN Bytes; + UINTN Index; + EFI_PHYSICAL_ADDRESS PhyAddr; + + DEBUG((EFI_D_INIT, "+++OhciInitFrameList()\n")); + + // + // The Frame List is a common buffer that will be + // accessed by both the cpu and the usb bus master + // at the same time. The Frame List ocupies 4K bytes, + // and must be aligned on 4-Kbyte boundaries. + // + Bytes = 4096; + Pages = EFI_SIZE_TO_PAGES (Bytes); + + Status = Ohc->PciIo->AllocateBuffer ( + Ohc->PciIo, + AllocateAnyPages, + EfiBootServicesData, + Pages, + &Buffer, + 0 + ); + + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "FAIL! AllocateBuffer\n")); + return EFI_OUT_OF_RESOURCES; + } + + Status = Ohc->PciIo->Map ( + Ohc->PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + Buffer, + &Bytes, + &MappedAddr, + &Mapping + ); + +#if 1 + if (EFI_ERROR (Status) || (Bytes != 4096)) { + DEBUG((EFI_D_ERROR, "FAIL! Map\n")); + Status = EFI_UNSUPPORTED; + return Status; + } + + Ohc->Hcca = (UINT32 *) (UINTN) Buffer; + Ohc->HccaMapping = Mapping; + + OhciWriteReg(Ohc, HC_HCCA_OFFSET, (UINT32)Buffer); + + return EFI_SUCCESS; + +#else + if (EFI_ERROR (Status) || (Bytes != 4096)) { + DEBUG((EFI_D_ERROR, "FAIL! Map\n")); + Status = EFI_UNSUPPORTED; + goto ON_ERROR; + } + + + Ohc->FrameBase = (UINT32 *) (UINTN) Buffer; + Ohc->FrameMapping = Mapping; + + // + // Tell the Host Controller where the Frame List lies, + // by set the Frame List Base Address Register. + // + //OhciSetFrameListBaseAddr (Ohc->PciIo, (VOID *) (UINTN) MappedAddr); + + // + // Allocate the QH used by sync interrupt/control/bulk transfer. + // FS ctrl/bulk queue head is set to loopback so additional BW + // can be reclaimed. Notice, LS don't support bulk transfer and + // also doesn't support BW reclamation. + // + Ohc->SyncIntQh = OhciCreateQh (Ohc, 1); + Ohc->CtrlQh = OhciCreateQh (Ohc, 1); + Ohc->BulkQh = OhciCreateQh (Ohc, 1); + + if ((Ohc->SyncIntQh == NULL) || (Ohc->CtrlQh == NULL) || (Ohc->BulkQh == NULL)) { + Ohc->PciIo->Unmap (Ohc->PciIo, Mapping); + DEBUG((EFI_D_ERROR, "FAIL! NULL1\n")); + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // +-------------+ + // | | + // Link the three together: SyncIntQh->CtrlQh->BulkQh <---------+ + // Each frame entry is linked to this sequence of QH. These QH + // will remain on the schedul, never got removed + // + PhyAddr = UsbHcGetPciAddressForHostMem (Ohc->MemPool, Ohc->CtrlQh, sizeof (OHCI_QH_HW)); + Ohc->SyncIntQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); + Ohc->SyncIntQh->NextQh = Ohc->CtrlQh; + + PhyAddr = UsbHcGetPciAddressForHostMem (Ohc->MemPool, Ohc->BulkQh, sizeof (OHCI_QH_HW)); + Ohc->CtrlQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); + Ohc->CtrlQh->NextQh = Ohc->BulkQh; + + // + // Some old platform such as Intel's Tiger 4 has a difficult time + // in supporting the full speed bandwidth reclamation in the previous + // mentioned form. Most new platforms don't suffer it. + // + Ohc->BulkQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); + + Ohc->BulkQh->NextQh = NULL; + + Ohc->FrameBaseHostAddr = AllocateZeroPool (4096); + if (Ohc->FrameBaseHostAddr == NULL) { + DEBUG((EFI_D_ERROR, "FAIL! NULL2\n")); + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + PhyAddr = UsbHcGetPciAddressForHostMem (Ohc->MemPool, Ohc->SyncIntQh, sizeof (OHCI_QH_HW)); + for (Index = 0; Index < OHCI_FRAME_NUM; Index++) { + Ohc->FrameBase[Index] = QH_HLINK (PhyAddr, FALSE); + Ohc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Ohc->SyncIntQh; + } + + DEBUG((EFI_D_INIT, "---OhciInitFrameList()\n")); + + return EFI_SUCCESS; + +ON_ERROR: + if (Ohc->SyncIntQh != NULL) { + UsbHcFreeMem (Ohc->MemPool, Ohc->SyncIntQh, sizeof (OHCI_QH_SW)); + } + + if (Ohc->CtrlQh != NULL) { + UsbHcFreeMem (Ohc->MemPool, Ohc->CtrlQh, sizeof (OHCI_QH_SW)); + } + + if (Ohc->BulkQh != NULL) { + UsbHcFreeMem (Ohc->MemPool, Ohc->BulkQh, sizeof (OHCI_QH_SW)); + } + + Ohc->PciIo->FreeBuffer (Ohc->PciIo, Pages, Buffer); + return Status; +#endif +} + + +/** + Destory FrameList buffer. + + @param Ohc The OHCI device. + +**/ +VOID +OhciDestoryFrameList ( + IN USB_HC_DEV *Ohc + ) +{ + // + // Unmap the common buffer for framelist entry, + // and free the common buffer. + // Ohci's frame list occupy 4k memory. + // + DEBUG((EFI_D_INIT, "+++OhciDestoryFrameList()\n")); + +#if 1 +#else + Ohc->PciIo->Unmap (Ohc->PciIo, Ohc->FrameMapping); + + Ohc->PciIo->FreeBuffer ( + Ohc->PciIo, + EFI_SIZE_TO_PAGES (4096), + (VOID *) Ohc->FrameBase + ); + + if (Ohc->FrameBaseHostAddr != NULL) { + FreePool (Ohc->FrameBaseHostAddr); + } + + if (Ohc->SyncIntQh != NULL) { + UsbHcFreeMem (Ohc->MemPool, Ohc->SyncIntQh, sizeof (OHCI_QH_SW)); + } + + if (Ohc->CtrlQh != NULL) { + UsbHcFreeMem (Ohc->MemPool, Ohc->CtrlQh, sizeof (OHCI_QH_SW)); + } + + if (Ohc->BulkQh != NULL) { + UsbHcFreeMem (Ohc->MemPool, Ohc->BulkQh, sizeof (OHCI_QH_SW)); + } + + Ohc->FrameBase = NULL; + Ohc->FrameBaseHostAddr = NULL; + Ohc->SyncIntQh = NULL; + Ohc->CtrlQh = NULL; + Ohc->BulkQh = NULL; +#endif + DEBUG((EFI_D_INIT, "---OhciDestoryFrameList()\n")); +} + + +/** + Convert the poll rate to the maxium 2^n that is smaller + than Interval. + + @param Interval The poll rate to convert. + + @return The converted poll rate. + +**/ +UINTN +OhciConvertPollRate ( + IN UINTN Interval + ) +{ + UINTN BitCount; + + ASSERT (Interval != 0); + + // + // Find the index (1 based) of the highest non-zero bit + // + BitCount = 0; + + while (Interval != 0) { + Interval >>= 1; + BitCount++; + } + + return (UINTN)1 << (BitCount - 1); +} + + +/** + Link a queue head (for asynchronous interrupt transfer) to + the frame list. + + @param Ohc The OHCI device. + @param Qh The queue head to link into. + +**/ +VOID +OhciLinkQhToFrameList ( + USB_HC_DEV *Ohc, + OHCI_QH_SW *Qh + ) +{ + UINTN Index; + OHCI_QH_SW *Prev; + OHCI_QH_SW *Next; + EFI_PHYSICAL_ADDRESS PhyAddr; + EFI_PHYSICAL_ADDRESS QhPciAddr; + +#if 1 +#else + ASSERT ((Ohc->FrameBase != NULL) && (Qh != NULL)); + + QhPciAddr = UsbHcGetPciAddressForHostMem (Ohc->MemPool, Qh, sizeof (OHCI_QH_HW)); + + for (Index = 0; Index < OHCI_FRAME_NUM; Index += Qh->Interval) { + // + // First QH can't be NULL because we always keep static queue + // heads on the frame list + // + ASSERT (!LINK_TERMINATED (Ohc->FrameBase[Index])); + Next = (OHCI_QH_SW*)(UINTN)Ohc->FrameBaseHostAddr[Index]; + Prev = NULL; + + // + // Now, insert the queue head (Qh) into this frame: + // 1. Find a queue head with the same poll interval, just insert + // Qh after this queue head, then we are done. + // + // 2. Find the position to insert the queue head into: + // Previous head's interval is bigger than Qh's + // Next head's interval is less than Qh's + // Then, insert the Qh between then + // + // This method is very much the same as that used by EHCI. + // Because each QH's interval is round down to 2^n, poll + // rate is correct. + // + while (Next->Interval > Qh->Interval) { + Prev = Next; + Next = Next->NextQh; + ASSERT (Next != NULL); + } + + // + // The entry may have been linked into the frame by early insertation. + // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh + // with Qh.Interval == 8 on the frame. If so, we are done with this frame. + // It isn't necessary to compare all the QH with the same interval to + // Qh. This is because if there is other QH with the same interval, Qh + // should has been inserted after that at FrameBase[0] and at FrameBase[0] it is + // impossible (Next == Qh) + // + if (Next == Qh) { + continue; + } + + if (Next->Interval == Qh->Interval) { + // + // If there is a QH with the same interval, it locates at + // FrameBase[0], and we can simply insert it after this QH. We + // are all done. + // + ASSERT ((Index == 0) && (Qh->NextQh == NULL)); + + Prev = Next; + Next = Next->NextQh; + + Qh->NextQh = Next; + Prev->NextQh = Qh; + + Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink; + + Prev->QhHw.HorizonLink = QH_HLINK (QhPciAddr, FALSE); + break; + } + + // + // OK, find the right position, insert it in. If Qh's next + // link has already been set, it is in position. This is + // guarranted by 2^n polling interval. + // + if (Qh->NextQh == NULL) { + Qh->NextQh = Next; + PhyAddr = UsbHcGetPciAddressForHostMem (Ohc->MemPool, Next, sizeof (OHCI_QH_HW)); + Qh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); + } + + if (Prev == NULL) { + Ohc->FrameBase[Index] = QH_HLINK (QhPciAddr, FALSE); + Ohc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Qh; + } else { + Prev->NextQh = Qh; + Prev->QhHw.HorizonLink = QH_HLINK (QhPciAddr, FALSE); + } + } +#endif +} + + +/** + Unlink QH from the frame list is easier: find all + the precedence node, and pointer there next to QhSw's + next. + + @param Ohc The OHCI device. + @param Qh The queue head to unlink. + +**/ +VOID +OhciUnlinkQhFromFrameList ( + USB_HC_DEV *Ohc, + OHCI_QH_SW *Qh + ) +{ + UINTN Index; + OHCI_QH_SW *Prev; + OHCI_QH_SW *This; +#if 1 +#else + ASSERT ((Ohc->FrameBase != NULL) && (Qh != NULL)); + + for (Index = 0; Index < OHCI_FRAME_NUM; Index += Qh->Interval) { + // + // Frame link can't be NULL because we always keep static + // queue heads on the frame list + // + ASSERT (!LINK_TERMINATED (Ohc->FrameBase[Index])); + This = (OHCI_QH_SW*)(UINTN)Ohc->FrameBaseHostAddr[Index]; + Prev = NULL; + + // + // Walk through the frame's QH list to find the + // queue head to remove + // + while ((This != NULL) && (This != Qh)) { + Prev = This; + This = This->NextQh; + } + + // + // Qh may have already been unlinked from this frame + // by early action. + // + if (This == NULL) { + continue; + } + + if (Prev == NULL) { + // + // Qh is the first entry in the frame + // + Ohc->FrameBase[Index] = Qh->QhHw.HorizonLink; + Ohc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Qh->NextQh; + } else { + Prev->NextQh = Qh->NextQh; + Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink; + } + } +#endif +} + + +/** + Check TDs Results. + + @param Ohc This OHCI device. + @param Td OHCI_TD_HW to check. + @param IsLow Is Low Speed Device. + @param QhResult Return the result of this TD list. + + @return Whether the TD's result is finialized. + +**/ +BOOLEAN +OhciCheckTdStatus ( + IN USB_HC_DEV *Ohc, + IN OHCI_ED_HW *Ed, + IN BOOLEAN IsLow, + OUT OHCI_QH_RESULT *QhResult, + IN UINT8 Class + ) +{ + UINTN Len; + UINT8 State; + BOOLEAN Finished; + OHCI_TD_SW *CurTdSw; + OHCI_TD_HW *TdHw; + + Finished = TRUE; + + if(Class == HC_CLASS_CONTROL) + CurTdSw = Ohc->CtrlQh; + else // HC_CLASS_INTERRUPT + CurTdSw = Ohc->IntrQh; + + TdHw = CurTdSw->TdHw; + // + // Initialize the data toggle to that of the first + // TD. The next toggle to use is either: + // 1. first TD's toggle if no TD is executed OK + // 2. the next toggle of last executed-OK TD + // + QhResult->Result = EFI_USB_NOERROR; + QhResult->NextToggle = (UINT8)(TdHw->gtd_info.b.data_toggle & 1); + QhResult->Complete = 0; + +#if 1 + if(Class == HC_CLASS_CONTROL) + { + while(Ohc->Hcca->done_head != Ohc->LastTd) + { + DEBUG((EFI_D_ERROR, ".\n")); + OhciWriteReg(Ohc, HC_INT_STATUS_OFFSET, 0x2); + } + } + else + { + OhciWriteReg(Ohc, HC_INT_STATUS_OFFSET, 0x2); + if(Ohc->Hcca->done_head != Ohc->LastTd) + { + Finished = FALSE; + QhResult->Complete = 0; + return Finished; + } + } + + Ohc->Hcca->done_head = NULL; + DEBUG((EFI_D_ERROR, ">\n")); + + while (TdHw != NULL) { + if(TdHw->current_buf_ptr == NULL) + { + if(TdHw->gtd_info.b.error_count != 0) + { + QhResult->Result |= EFI_USB_ERR_NOTEXECUTE; + DEBUG((EFI_D_ERROR, "FAIL! EXECUTE ERROR1\n")); + Finished = TRUE; + OhciDumpSWTds(Ohc->CtrlQh); + OhcDumpRegs(Ohc); + goto ON_EXIT; + } + + if(TdHw->gtd_info.b.condition_code != 0) + { + switch(TdHw->gtd_info.b.condition_code) + { + case 4: //stall + QhResult->Result |= EFI_USB_ERR_STALL; + DEBUG((EFI_D_ERROR, "FAIL! EFI_USB_ERR_STALL\n")); + break; + default : + QhResult->Result |= EFI_USB_ERR_NOTEXECUTE; + DEBUG((EFI_D_ERROR, "FAIL! EXECUTE ERROR2\n")); + break; + } + + Finished = TRUE; + OhciDumpSWTds(Ohc->CtrlQh); + OhcDumpRegs(Ohc); + goto ON_EXIT; + } + + QhResult->NextToggle = (TdHw->gtd_info.b.data_toggle & 1) ? 0 : 1; + // + // This TD is finished OK or met short packet read. Update the + // transfer length if it isn't a SETUP. + // + + if (TdHw->gtd_info.b.pid != SETUP_PACKET_ID) { + QhResult->Complete += CurTdSw->DataLen; + } + + // + // Short packet condition for full speed input TD, also + // terminate the transfer + // + /* + if (!IsLow && (TdHw->ShortPacket == 1) && (Len < Td->DataLen)) { + DEBUG ((EFI_D_INFO, "OhciCheckTdStatus: short packet read occured\n")); + + Finished = TRUE; + goto ON_EXIT; + }*/ + } // if(TdHw->current_buf_ptr == NULL) + /*else + { + QhResult->Result |= EFI_USB_ERR_NOTEXECUTE; + DEBUG((EFI_D_ERROR, "FAIL! EXECUTE ERROR3\n")); + Finished = TRUE; + goto ON_EXIT; + }*/ + CurTdSw = CurTdSw->NextTd; + TdHw = CurTdSw->TdHw; + } + + if(!Finished) + { + OhciDumpSWTds(Ohc->CtrlQh); + OhcDumpRegs(Ohc); + } +#else + while (Td != NULL) { + TdHw = &Td->TdHw; + State = (UINT8)TdHw->Status; + + // + // OHCI will set STALLED bit when it abort the execution + // of TD list. There are several reasons: + // 1. BABBLE error happened + // 2. Received a STALL response + // 3. Error count decreased to zero. + // + // It also set CRC/Timeout/NAK/Buffer Error/BitStuff Error + // bits when corresponding conditions happen. But these + // conditions are not deadly, that is a TD can successfully + // completes even these bits are set. But it is likely that + // upper layer won't distinguish these condtions. So, only + // set these bits when TD is actually halted. + // + if ((State & USBTD_STALLED) != 0) { + if ((State & USBTD_BABBLE) != 0) { + QhResult->Result |= EFI_USB_ERR_BABBLE; + + } else if (TdHw->ErrorCount != 0) { + QhResult->Result |= EFI_USB_ERR_STALL; + } + + if ((State & USBTD_CRC) != 0) { + QhResult->Result |= EFI_USB_ERR_CRC; + } + + if ((State & USBTD_BUFFERR) != 0) { + QhResult->Result |= EFI_USB_ERR_BUFFER; + } + + if ((Td->TdHw.Status & USBTD_BITSTUFF) != 0) { + QhResult->Result |= EFI_USB_ERR_BITSTUFF; + } + + if (TdHw->ErrorCount == 0) { + QhResult->Result |= EFI_USB_ERR_TIMEOUT; + } + + Finished = TRUE; + goto ON_EXIT; + + } else if ((State & USBTD_ACTIVE) != 0) { + // + // The TD is still active, no need to check further. + // + QhResult->Result |= EFI_USB_ERR_NOTEXECUTE; + + Finished = FALSE; + goto ON_EXIT; + + } else { + // + // Update the next data toggle, it is always the + // next to the last known-good TD's data toggle if + // any TD is executed OK + // + QhResult->NextToggle = (UINT8) (1 - (UINT8)TdHw->DataToggle); + + // + // This TD is finished OK or met short packet read. Update the + // transfer length if it isn't a SETUP. + // + Len = (TdHw->ActualLen + 1) & 0x7FF; + + if (TdHw->PidCode != SETUP_PACKET_ID) { + QhResult->Complete += Len; + } + + // + // Short packet condition for full speed input TD, also + // terminate the transfer + // + if (!IsLow && (TdHw->ShortPacket == 1) && (Len < Td->DataLen)) { + DEBUG ((EFI_D_INFO, "OhciCheckTdStatus: short packet read occured\n")); + + Finished = TRUE; + goto ON_EXIT; + } + } + + Td = Td->NextTd; + } +#endif + +ON_EXIT: + // + // Check whether HC is halted. Don't move this up. It must be + // called after data toggle is successfully updated. + // + if (!OhciIsHcWorking (Ohc->PciIo)) { + QhResult->Result |= EFI_USB_ERR_SYSTEM; + Finished = TRUE; + } + + if (Finished) { + Ohc->PciIo->Flush (Ohc->PciIo); + } + + OhciAckAllInterrupt (Ohc); + return Finished; +} + + +/** + Check the result of the transfer. + + @param Ohc The OHCI device. + @param Qh The queue head of the transfer. + @param Td The first TDs of the transfer. + @param TimeOut TimeOut value in milliseconds. + @param IsLow Is Low Speed Device. + @param QhResult The variable to return result. + + @retval EFI_SUCCESS The transfer finished with success. + @retval EFI_DEVICE_ERROR Transfer failed. + +**/ +EFI_STATUS +OhciExecuteTransfer ( + IN USB_HC_DEV *Ohc, + IN OHCI_ED_HW *Ed, + IN UINTN TimeOut, + IN BOOLEAN IsLow, + OUT OHCI_QH_RESULT *QhResult + ) +{ + UINTN Index; + UINTN Delay; + BOOLEAN Finished; + EFI_STATUS Status; + + DEBUG((EFI_D_INIT, "+++OhciExecuteTransfer()\n")); + + Finished = FALSE; + Status = EFI_SUCCESS; + Delay = (TimeOut * OHC_1_MILLISECOND / OHC_SYNC_POLL_INTERVAL) + 1; + + for (Index = 0; Index < Delay; Index++) { + Finished = OhciCheckTdStatus (Ohc, Ed, IsLow, QhResult, HC_CLASS_CONTROL); + + // + // Transfer is OK or some error occured (TD inactive) + // + if (Finished) { + DEBUG((EFI_D_INIT, "SUCCESS! OhciExecuteTransfer\n")); + break; + } + + gBS->Stall (OHC_SYNC_POLL_INTERVAL); + } + + if (!Finished) { + DEBUG ((EFI_D_ERROR, "OhciExecuteTransfer: execution not finished for %dms\n", (UINT32)TimeOut)); + //OhciDumpQh (Qh); + //OhciDumpTds (Td); + + Status = EFI_TIMEOUT; + + } else if (QhResult->Result != EFI_USB_NOERROR) { + DEBUG ((EFI_D_ERROR, "OhciExecuteTransfer: execution failed with result %x\n", QhResult->Result)); + //OhciDumpQh (Qh); + //OhciDumpTds (Td); + + Status = EFI_DEVICE_ERROR; + } + + DEBUG((EFI_D_INIT, "---OhciExecuteTransfer()\n")); + + return Status; +} + + +/** + Update Async Request, QH and TDs. + + @param Ohc The OHCI device. + @param AsyncReq The OHCI asynchronous transfer to update. + @param Result Transfer reslut. + @param NextToggle The toggle of next data. + +**/ +VOID +OhciUpdateAsyncReq ( + IN USB_HC_DEV *Ohc, + IN OHCI_ASYNC_REQUEST *AsyncReq, + IN UINT32 Result, + IN UINT32 NextToggle + ) +{ + OHCI_ED_HW *EdHw; + OHCI_TD_SW *FirstTd; + OHCI_TD_SW *Td; + OHCI_TD_HW *TdHw; + + UINT8 *DataPtr, *DataPhy; + + //DEBUG((EFI_D_INIT, "+++OhciUpdateAsyncReq()\n")); + + EdHw = AsyncReq->EdHw; + FirstTd = AsyncReq->TdSw; + + if (Result == EFI_USB_NOERROR) { + // + // The last transfer succeeds. Then we need to update + // the Qh and Td for next round of transfer. + // 1. Update the TD's data toggle + // 2. Activate all the TDs + // 3. Link the TD to the queue head again since during + // execution, queue head's TD pointer is changed by + // hardware. + // + + for (Td = FirstTd; Td != NULL; Td = Td->NextTd) { + TdHw = Td->TdHw; + if(TdHw != NULL) + { + // + // Allocate and map source data buffer for bus master access. + // + DataPtr = UsbHcAllocateMem (Ohc->MemPool, Td->DataLen); + + if (DataPtr == NULL) { + DEBUG((EFI_D_ERROR, "FAIL! UsbHcAllocateMem\n")); + return; + } + + DataPhy = (UINT8 *) (UINTN) UsbHcGetPciAddressForHostMem (Ohc->MemPool, DataPtr, Td->DataLen); + + Ohc->Destory = Td->Data; + Ohc->DestroySize = Td->DataLen; + TdHw->current_buf_ptr = DataPhy; + TdHw->buffer_end = DataPhy + Td->DataLen - 1; + TdHw->gtd_info.b.data_toggle = NextToggle + 2; + + if(Td->NextTd) + { + TdHw->next_td = Td->NextTd->TdHw; + } + + NextToggle = NextToggle ? 0 : 1; + } + } + + EdHw->head_td_ptr = FirstTd->TdHw; + + //OhciDumpEd(EdHw); + + OhciLinkTdToQh (Ohc, EdHw, HC_CLASS_INTERRUPT); + + //DEBUG((EFI_D_INIT, "---OhciUpdateAsyncReq()\n")); + + return ; + } +} + + +/** + Create Async Request node, and Link to List. + + @param Ohc The OHCI device. + @param Qh The queue head of the transfer. + @param FirstTd First TD of the transfer. + @param DevAddr Device Address. + @param EndPoint EndPoint Address. + @param DataLen Data length. + @param Interval Polling Interval when inserted to frame list. + @param Data Data buffer, unmapped. + @param Callback Callback after interrupt transfeer. + @param Context Callback Context passed as function parameter. + @param IsLow Is Low Speed. + + @retval EFI_SUCCESS An asynchronous transfer is created. + @retval EFI_INVALID_PARAMETER Paremeter is error. + @retval EFI_OUT_OF_RESOURCES Failed because of resource shortage. + +**/ +EFI_STATUS +OhciCreateAsyncReq ( + IN USB_HC_DEV *Ohc, + IN OHCI_ED_HW *EdHw, + IN OHCI_TD_SW *TdSw, + IN UINT8 DevAddr, + IN UINT8 EndPoint, + IN UINTN DataLen, + IN UINTN Interval, + IN UINT8 *Data, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, + IN VOID *Context, + IN BOOLEAN IsLow + ) +{ + OHCI_ASYNC_REQUEST *AsyncReq; + + DEBUG((EFI_D_INIT, "+++OhciCreateAsyncReq()\n")); + + AsyncReq = AllocatePool (sizeof (OHCI_ASYNC_REQUEST)); + + if (AsyncReq == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Fill Request field. Data is allocated host memory, not mapped + // + AsyncReq->Signature = OHCI_ASYNC_INT_SIGNATURE; + AsyncReq->DevAddr = DevAddr; + AsyncReq->EndPoint = EndPoint; + AsyncReq->DataLen = DataLen; + AsyncReq->Interval = OhciConvertPollRate(Interval); + AsyncReq->Data = Data; + AsyncReq->Callback = Callback; + AsyncReq->Context = Context; + AsyncReq->EdHw = EdHw; + AsyncReq->TdSw = TdSw; + AsyncReq->IsLow = IsLow; + + // + // Insert the new interrupt transfer to the head of the list. + // The interrupt transfer's monitor function scans the whole + // list from head to tail. The new interrupt transfer MUST be + // added to the head of the list. + // + InsertHeadList (&(Ohc->AsyncIntList), &(AsyncReq->Link)); + + DEBUG((EFI_D_INIT, "---OhciCreateAsyncReq()\n")); + + return EFI_SUCCESS; +} + + +/** + Free an asynchronous request's resource such as memory. + + @param Ohc The OHCI device. + @param AsyncReq The asynchronous request to free. + +**/ +VOID +OhciFreeAsyncReq ( + IN USB_HC_DEV *Ohc, + IN OHCI_ASYNC_REQUEST *AsyncReq + ) +{ + ASSERT ((Ohc != NULL) && (AsyncReq != NULL)); + + DEBUG((EFI_D_ERROR, "+++OhciFreeAsyncReq()\n")); + + OhciDestoryTds (Ohc, AsyncReq->TdSw); + + if (AsyncReq->Data != NULL) { + UsbHcFreeMem (Ohc->MemPool, AsyncReq->Data, AsyncReq->DataLen); + } + + gBS->FreePool (AsyncReq); + + DEBUG((EFI_D_ERROR, "+++OhciFreeAsyncReq()\n")); +} + + +/** + Unlink an asynchronous request's from OHC's asynchronus list. + also remove the queue head from the frame list. If FreeNow, + release its resource also. Otherwise, add the request to the + OHC's recycle list to wait for a while before release the memory. + Until then, hardware won't hold point to the request. + + @param Ohc The OHCI device. + @param AsyncReq The asynchronous request to free. + @param FreeNow If TRUE, free the resource immediately, otherwise + add the request to recycle wait list. + +**/ +VOID +OhciUnlinkAsyncReq ( + IN USB_HC_DEV *Ohc, + IN OHCI_ASYNC_REQUEST *AsyncReq, + IN BOOLEAN FreeNow + ) +{ + ASSERT ((Ohc != NULL) && (AsyncReq != NULL)); + + DEBUG((EFI_D_INIT, "+++OhciUnlinkAsyncReq()\n")); +#if 1 +#else + RemoveEntryList (&(AsyncReq->Link)); + OhciUnlinkQhFromFrameList (Ohc, AsyncReq->QhSw); + + if (FreeNow) { + OhciFreeAsyncReq (Ohc, AsyncReq); + } else { + // + // To sychronize with hardware, mark the queue head as inactive + // then add AsyncReq to OHC's recycle list + // + AsyncReq->QhSw->QhHw.VerticalLink = QH_VLINK (NULL, TRUE); + AsyncReq->Recycle = Ohc->RecycleWait; + Ohc->RecycleWait = AsyncReq; + } +#endif + DEBUG((EFI_D_INIT, "---OhciUnlinkAsyncReq()\n")); +} + + +/** + Delete Async Interrupt QH and TDs. + + @param Ohc The OHCI device. + @param DevAddr Device Address. + @param EndPoint EndPoint Address. + @param Toggle The next data toggle to use. + + @retval EFI_SUCCESS The request is deleted. + @retval EFI_INVALID_PARAMETER Paremeter is error. + @retval EFI_NOT_FOUND The asynchronous isn't found. + +**/ +EFI_STATUS +OhciRemoveAsyncReq ( + IN USB_HC_DEV *Ohc, + IN UINT8 DevAddr, + IN UINT8 EndPoint, + OUT UINT8 *Toggle + ) +{ + EFI_STATUS Status; + OHCI_ASYNC_REQUEST *AsyncReq; + OHCI_QH_RESULT QhResult; + LIST_ENTRY *Link; + BOOLEAN Found; + + Status = EFI_SUCCESS; + + // + // If no asynchronous interrupt transaction exists + // + if (IsListEmpty (&(Ohc->AsyncIntList))) { + return EFI_SUCCESS; + } + + // + // Find the asynchronous transfer to this device/endpoint pair + // + Found = FALSE; + Link = Ohc->AsyncIntList.ForwardLink; + + do { + AsyncReq = OHCI_ASYNC_INT_FROM_LINK (Link); + Link = Link->ForwardLink; + + if ((AsyncReq->DevAddr == DevAddr) && (AsyncReq->EndPoint == EndPoint)) { + Found = TRUE; + break; + } + + } while (Link != &(Ohc->AsyncIntList)); + + if (!Found) { + return EFI_NOT_FOUND; + } + + // + // Check the result of the async transfer then update it + // to get the next data toggle to use. + // + OhciCheckTdStatus (Ohc, AsyncReq->EdHw, AsyncReq->IsLow, &QhResult, HC_CLASS_INTERRUPT); + *Toggle = QhResult.NextToggle; + + // + // Don't release the request now, keep it to synchronize with hardware. + // + OhciUnlinkAsyncReq (Ohc, AsyncReq, FALSE); + return Status; +} + + +/** + Recycle the asynchronouse request. When a queue head + is unlinked from frame list, host controller hardware + may still hold a cached pointer to it. To synchronize + with hardware, the request is released in two steps: + first it is linked to the OHC's RecycleWait list. At + the next time OhciMonitorAsyncReqList is fired, it is + moved to OHC's Recylelist. Then, at another timer + activation, all the requests on Recycle list is freed. + This guarrantes that each unlink queue head keeps + existing for at least 50ms, far enough for the hardware + to clear its cache. + + @param Ohc The OHCI device. + +**/ +VOID +OhciRecycleAsyncReq ( + IN USB_HC_DEV *Ohc + ) +{ + OHCI_ASYNC_REQUEST *Req; + OHCI_ASYNC_REQUEST *Next; + + Req = Ohc->Recycle; + + while (Req != NULL) { + Next = Req->Recycle; + OhciFreeAsyncReq (Ohc, Req); + Req = Next; + } + + Ohc->Recycle = Ohc->RecycleWait; + Ohc->RecycleWait = NULL; +} + + + +/** + Release all the asynchronous transfers on the lsit. + + @param Ohc The OHCI device. + +**/ +VOID +OhciFreeAllAsyncReq ( + IN USB_HC_DEV *Ohc + ) +{ + LIST_ENTRY *Head; + OHCI_ASYNC_REQUEST *AsyncReq; + + DEBUG((EFI_D_INIT, "+++OhciFreeAllAsyncReq()\n")); + + // + // Call OhciRecycleAsyncReq twice. The requests on Recycle + // will be released at the first call; The requests on + // RecycleWait will be released at the second call. + // + OhciRecycleAsyncReq (Ohc); + OhciRecycleAsyncReq (Ohc); + + Head = &(Ohc->AsyncIntList); + + if (IsListEmpty (Head)) { + return; + } + + while (!IsListEmpty (Head)) { + AsyncReq = OHCI_ASYNC_INT_FROM_LINK (Head->ForwardLink); + OhciUnlinkAsyncReq (Ohc, AsyncReq, TRUE); + } + + DEBUG((EFI_D_INIT, "---OhciFreeAllAsyncReq()\n")); +} + + +/** + Interrupt transfer periodic check handler. + + @param Event The event of the time. + @param Context Context of the event, pointer to USB_HC_DEV. + +**/ +VOID +EFIAPI +OhciMonitorAsyncReqList ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + OHCI_ASYNC_REQUEST *AsyncReq; + LIST_ENTRY *Link; + USB_HC_DEV *Ohc; + VOID *Data; + BOOLEAN Finished; + OHCI_QH_RESULT QhResult; + UINT32 Inputs; + + DEBUG((EFI_D_INFO, "++%a : %d\n", __FUNCTION__, __LINE__)); + + Ohc = (USB_HC_DEV *) Context; + + // + // Recycle the asynchronous requests expired, and promote + // requests waiting to be recycled the next time when this + // timer expires + // + + if(Ohc->Destory) + { + DEBUG((EFI_D_ERROR, "%a (Destoryed) : %d\n", __FUNCTION__, __LINE__)); + UsbHcFreeMem (Ohc->MemPool, Ohc->Destory, Ohc->DestroySize); + Ohc->Destory = NULL; + Ohc->DestroySize = 0; + } + //OhciRecycleAsyncReq (Ohc); + + if (IsListEmpty (&(Ohc->AsyncIntList))) { + DEBUG((EFI_D_ERROR, "%a (IsListEmpty) : %d\n", __FUNCTION__, __LINE__)); + return ; + } + + // + // This loop must be delete safe + // + Link = Ohc->AsyncIntList.ForwardLink; + + do { + AsyncReq = OHCI_ASYNC_INT_FROM_LINK (Link); + Link = Link->ForwardLink; + + Finished = OhciCheckTdStatus (Ohc, AsyncReq->EdHw, AsyncReq->IsLow, &QhResult, HC_CLASS_INTERRUPT); + + if (!Finished) { + continue; + } + + // + // Copy the data to temporary buffer if there are some + // data transferred. We may have zero-length packet + // + Data = NULL; + + if (QhResult.Complete != 0) { + Data = AllocatePool (QhResult.Complete); + + if (Data == NULL) { + return ; + } + + CopyMem (Data, AsyncReq->TdSw->Data, QhResult.Complete); + + Inputs = QhResult.Complete; + DEBUG((EFI_D_INIT, "INPUT : ")); + while(Inputs--) + { + DEBUG((EFI_D_INIT, "0x%02X ", ((UINT8*)Data)[QhResult.Complete - Inputs -1])); + } + DEBUG((EFI_D_INIT, "\n")); + } + + OhciUpdateAsyncReq (Ohc, AsyncReq, QhResult.Result, QhResult.NextToggle); + + // + // Now, either transfer is SUCCESS or met errors since + // we have skipped to next transfer earlier if current + // transfer is still active. + // + if (QhResult.Result == EFI_USB_NOERROR) { + AsyncReq->Callback (Data, QhResult.Complete, AsyncReq->Context, QhResult.Result); + } else { + // + // Leave error recovery to its related device driver. + // A common case of the error recovery is to re-submit + // the interrupt transfer. When an interrupt transfer + // is re-submitted, its position in the linked list is + // changed. It is inserted to the head of the linked + // list, while this function scans the whole list from + // head to tail. Thus, the re-submitted interrupt transfer's + // callback function will not be called again in this round. + // + AsyncReq->Callback (NULL, 0, AsyncReq->Context, QhResult.Result); + } + + if (Data != NULL) { + gBS->FreePool (Data); + } + } while (Link != &(Ohc->AsyncIntList)); + + DEBUG((EFI_D_INFO, "--%a : %d\n", __FUNCTION__, __LINE__)); +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciSched.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciSched.h new file mode 100644 index 000000000..2a3fd7c13 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/OhciSched.h @@ -0,0 +1,270 @@ +/** @file + + The definition for EHCI register operation routines. + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_OHCI_SCHED_H_ +#define _EFI_OHCI_SCHED_H_ + + +#define OHCI_ASYNC_INT_SIGNATURE SIGNATURE_32 ('u', 'h', 'c', 'a') +// +// The failure mask for USB transfer return status. If any of +// these bit is set, the transfer failed. EFI_USB_ERR_NOEXECUTE +// and EFI_USB_ERR_NAK are not considered as error condition: +// the transfer is still going on. +// +#define USB_ERR_FAIL_MASK (EFI_USB_ERR_STALL | EFI_USB_ERR_BUFFER | \ + EFI_USB_ERR_BABBLE | EFI_USB_ERR_CRC | \ + EFI_USB_ERR_TIMEOUT | EFI_USB_ERR_BITSTUFF | \ + EFI_USB_ERR_SYSTEM) + + +// +// Structure to return the result of OHCI QH execution. +// Result is the final result of the QH's QTD. NextToggle +// is the next data toggle to use. Complete is the actual +// length of data transferred. +// +typedef struct { + UINT32 Result; + UINT8 NextToggle; + UINTN Complete; +} OHCI_QH_RESULT; + +typedef struct _OHCI_ASYNC_REQUEST OHCI_ASYNC_REQUEST; + +// +// Structure used to manager the asynchronous interrupt transfers. +// +struct _OHCI_ASYNC_REQUEST{ + UINTN Signature; + LIST_ENTRY Link; + OHCI_ASYNC_REQUEST *Recycle; + + // + // Endpoint attributes + // + UINT8 DevAddr; + UINT8 EndPoint; + BOOLEAN IsLow; + UINTN Interval; + + // + // Data and OHC structures + // + OHCI_TD_SW *TdSw; + OHCI_ED_HW *EdHw; + UINT8 *Data; // Allocated host memory, not mapped memory + UINTN DataLen; + VOID *Mapping; + + // + // User callback and its context + // + EFI_ASYNC_USB_TRANSFER_CALLBACK Callback; + VOID *Context; +}; + +#define OHCI_ASYNC_INT_FROM_LINK(a) \ + CR (a, OHCI_ASYNC_REQUEST, Link, OHCI_ASYNC_INT_SIGNATURE) + + +/** + Create Frame List Structure. + + @param Ohc The OHCI device. + + @return EFI_OUT_OF_RESOURCES Can't allocate memory resources. + @return EFI_UNSUPPORTED Map memory fail. + @return EFI_SUCCESS Success. + +**/ +EFI_STATUS +OhciInitFrameList ( + IN USB_HC_DEV *Ohc + ); + +/** + Destory FrameList buffer. + + @param Ohc The OHCI device. + + @return None. + +**/ +VOID +OhciDestoryFrameList ( + IN USB_HC_DEV *Ohc + ); + + +/** + Convert the poll rate to the maxium 2^n that is smaller + than Interval. + + @param Interval The poll rate to convert. + + @return The converted poll rate. + +**/ +UINTN +OhciConvertPollRate ( + IN UINTN Interval + ); + + +/** + Link a queue head (for asynchronous interrupt transfer) to + the frame list. + + @param Ohc The OHCI device. + @param Qh The queue head to link into. + +**/ +VOID +OhciLinkQhToFrameList ( + USB_HC_DEV *Ohc, + OHCI_QH_SW *Qh + ); + + +/** + Unlink QH from the frame list is easier: find all + the precedence node, and pointer there next to QhSw's + next. + + @param Ohc The OHCI device. + @param Qh The queue head to unlink. + +**/ +VOID +OhciUnlinkQhFromFrameList ( + USB_HC_DEV *Ohc, + OHCI_QH_SW *Qh + ); + + +/** + Check the result of the transfer. + + @param Ohc The OHCI device. + @param Qh The queue head of the transfer. + @param Td The first TDs of the transfer. + @param TimeOut TimeOut value in milliseconds. + @param IsLow Is Low Speed Device. + @param QhResult The variable to return result. + + @retval EFI_SUCCESS The transfer finished with success. + @retval EFI_DEVICE_ERROR Transfer failed. + +**/ +EFI_STATUS +OhciExecuteTransfer ( + IN USB_HC_DEV *Ohc, + IN OHCI_ED_HW *Ed, + IN UINTN TimeOut, + IN BOOLEAN IsLow, + OUT OHCI_QH_RESULT *QhResult + ); + + +/** + Create Async Request node, and Link to List. + + @param Ohc The OHCI device. + @param Qh The queue head of the transfer. + @param FirstTd First TD of the transfer. + @param DevAddr Device Address. + @param EndPoint EndPoint Address. + @param DataLen Data length. + @param Interval Polling Interval when inserted to frame list. + @param Data Data buffer, unmapped. + @param Callback Callback after interrupt transfeer. + @param Context Callback Context passed as function parameter. + @param IsLow Is Low Speed. + + @retval EFI_SUCCESS An asynchronous transfer is created. + @retval EFI_INVALID_PARAMETER Paremeter is error. + @retval EFI_OUT_OF_RESOURCES Failed because of resource shortage. + +**/ +EFI_STATUS +OhciCreateAsyncReq ( + IN USB_HC_DEV *Ohc, + IN OHCI_ED_HW *EdHw, + IN OHCI_TD_SW *TdSw, + IN UINT8 DevAddr, + IN UINT8 EndPoint, + IN UINTN DataLen, + IN UINTN Interval, + IN UINT8 *Data, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, + IN VOID *Context, + IN BOOLEAN IsLow + ); + + +/** + Delete Async Interrupt QH and TDs. + + @param Ohc The OHCI device. + @param DevAddr Device Address. + @param EndPoint EndPoint Address. + @param Toggle The next data toggle to use. + + @retval EFI_SUCCESS The request is deleted. + @retval EFI_INVALID_PARAMETER Paremeter is error. + @retval EFI_NOT_FOUND The asynchronous isn't found. + +**/ +EFI_STATUS +OhciRemoveAsyncReq ( + IN USB_HC_DEV *Ohc, + IN UINT8 DevAddr, + IN UINT8 EndPoint, + OUT UINT8 *Toggle + ); + + +/** + Release all the asynchronous transfers on the lsit. + + @param Ohc The OHCI device. + + @return None. + +**/ +VOID +OhciFreeAllAsyncReq ( + IN USB_HC_DEV *Ohc + ); + + +/** + Interrupt transfer periodic check handler. + + @param Event The event of the time. + @param Context Context of the event, pointer to USB_HC_DEV. + + @return None. + +**/ +VOID +EFIAPI +OhciMonitorAsyncReqList ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/UsbHcMem.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/UsbHcMem.c new file mode 100644 index 000000000..919c05023 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/UsbHcMem.c @@ -0,0 +1,564 @@ +/** @file + + The routine procedure for uhci memory allocate/free. + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ohci.h" + + +/** + Allocate a block of memory to be used by the buffer pool. + + @param Pool The buffer pool to allocate memory for. + @param Pages How many pages to allocate. + + @return The allocated memory block or NULL if failed. + +**/ +USBHC_MEM_BLOCK * +UsbHcAllocMemBlock ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Pages + ) +{ + USBHC_MEM_BLOCK *Block; + EFI_PCI_IO_PROTOCOL *PciIo; + VOID *BufHost; + VOID *Mapping; + EFI_PHYSICAL_ADDRESS MappedAddr; + UINTN Bytes; + EFI_STATUS Status; + + PciIo = Pool->PciIo; + + Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK)); + if (Block == NULL) { + return NULL; + } + + // + // each bit in the bit array represents USBHC_MEM_UNIT + // bytes of memory in the memory block. + // + ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE); + + Block->BufLen = EFI_PAGES_TO_SIZE (Pages); + Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8); + Block->Bits = AllocateZeroPool (Block->BitsLen); + + if (Block->Bits == NULL) { + gBS->FreePool (Block); + return NULL; + } + + // + // Allocate the number of Pages of memory, then map it for + // bus master read and write. + // + Status = PciIo->AllocateBuffer ( + PciIo, + AllocateAnyPages, + EfiBootServicesData, + Pages, + &BufHost, + 0 + ); + + if (EFI_ERROR (Status)) { + goto FREE_BITARRAY; + } + + Bytes = EFI_PAGES_TO_SIZE (Pages); + Status = PciIo->Map ( + PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + BufHost, + &Bytes, + &MappedAddr, + &Mapping + ); + + if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) { + goto FREE_BUFFER; + } + + // + // Check whether the data structure used by the host controller + // should be restricted into the same 4G + // + if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) { + PciIo->Unmap (PciIo, Mapping); + goto FREE_BUFFER; + } + + Block->BufHost = BufHost; + Block->Buf = (UINT8 *) ((UINTN) MappedAddr); + Block->Mapping = Mapping; + + return Block; + +FREE_BUFFER: + PciIo->FreeBuffer (PciIo, Pages, BufHost); + +FREE_BITARRAY: + gBS->FreePool (Block->Bits); + gBS->FreePool (Block); + return NULL; +} + + +/** + Free the memory block from the memory pool. + + @param Pool The memory pool to free the block from. + @param Block The memory block to free. + +**/ +VOID +UsbHcFreeMemBlock ( + IN USBHC_MEM_POOL *Pool, + IN USBHC_MEM_BLOCK *Block + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + + ASSERT ((Pool != NULL) && (Block != NULL)); + + PciIo = Pool->PciIo; + + // + // Unmap the common buffer then free the structures + // + PciIo->Unmap (PciIo, Block->Mapping); + PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost); + + gBS->FreePool (Block->Bits); + gBS->FreePool (Block); +} + + +/** + Alloc some memory from the block. + + @param Block The memory block to allocate memory from. + @param Units Number of memory units to allocate. + + @return EFI_SUCCESS The needed memory is allocated. + @return EFI_NOT_FOUND Can't find the free memory. + +**/ +VOID * +UsbHcAllocMemFromBlock ( + IN USBHC_MEM_BLOCK *Block, + IN UINTN Units + ) +{ + UINTN Byte; + UINT8 Bit; + UINTN StartByte; + UINT8 StartBit; + UINTN Available; + UINTN Count; + + ASSERT ((Block != 0) && (Units != 0)); + + StartByte = 0; + StartBit = 0; + Available = 0; + + for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) { + // + // If current bit is zero, the corresponding memory unit is + // available, otherwise we need to restart our searching. + // Available counts the consective number of zero bit. + // + if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) { + Available++; + + if (Available >= Units) { + break; + } + + NEXT_BIT (Byte, Bit); + + } else { + NEXT_BIT (Byte, Bit); + + Available = 0; + StartByte = Byte; + StartBit = Bit; + } + } + + if (Available < Units) { + return NULL; + } + + // + // Mark the memory as allocated + // + Byte = StartByte; + Bit = StartBit; + + for (Count = 0; Count < Units; Count++) { + ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit)); + NEXT_BIT (Byte, Bit); + } + + return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT; +} + +/** + Calculate the corresponding pci bus address according to the Mem parameter. + + @param Pool The memory pool of the host controller. + @param Mem The pointer to host memory. + @param Size The size of the memory region. + + @return the pci memory address +**/ +EFI_PHYSICAL_ADDRESS +UsbHcGetPciAddressForHostMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + UINTN AllocSize; + EFI_PHYSICAL_ADDRESS PhyAddr; + UINTN Offset; + + Head = Pool->Head; + AllocSize = USBHC_MEM_ROUND (Size); + + if (Mem == NULL) { + return 0; + } + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the allocated memory. + // + if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) { + break; + } + } + + ASSERT ((Block != NULL)); + // + // calculate the pci memory address for host memory address. + // + Offset = (UINT8 *)Mem - Block->BufHost; + PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset); + return PhyAddr; +} + +/** + Insert the memory block to the pool's list of the blocks. + + @param Head The head of the memory pool's block list. + @param Block The memory block to insert. + +**/ +VOID +UsbHcInsertMemBlockToPool ( + IN USBHC_MEM_BLOCK *Head, + IN USBHC_MEM_BLOCK *Block + ) +{ + ASSERT ((Head != NULL) && (Block != NULL)); + Block->Next = Head->Next; + Head->Next = Block; +} + + +/** + Is the memory block empty? + + @param Block The memory block to check. + + @return TRUE The memory block is empty. + @return FALSE The memory block isn't empty. + +**/ +BOOLEAN +UsbHcIsMemBlockEmpty ( + IN USBHC_MEM_BLOCK *Block + ) +{ + UINTN Index; + + for (Index = 0; Index < Block->BitsLen; Index++) { + if (Block->Bits[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Unlink the memory block from the pool's list. + + @param Head The block list head of the memory's pool. + @param BlockToUnlink The memory block to unlink. + +**/ +VOID +UsbHcUnlinkMemBlock ( + IN USBHC_MEM_BLOCK *Head, + IN USBHC_MEM_BLOCK *BlockToUnlink + ) +{ + USBHC_MEM_BLOCK *Block; + + ASSERT ((Head != NULL) && (BlockToUnlink != NULL)); + + for (Block = Head; Block != NULL; Block = Block->Next) { + if (Block->Next == BlockToUnlink) { + Block->Next = BlockToUnlink->Next; + BlockToUnlink->Next = NULL; + break; + } + } +} + + +/** + Initialize the memory management pool for the host controller. + + @param PciIo The PciIo that can be used to access the host controller. + @param Check4G Whether the host controller requires allocated memory + from one 4G address space. + @param Which4G The 4G memory area each memory allocated should be from. + + @return EFI_SUCCESS The memory pool is initialized. + @return EFI_OUT_OF_RESOURCE Fail to init the memory pool. + +**/ +USBHC_MEM_POOL * +UsbHcInitMemPool ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Check4G, + IN UINT32 Which4G + ) +{ + USBHC_MEM_POOL *Pool; + + Pool = AllocatePool (sizeof (USBHC_MEM_POOL)); + + if (Pool == NULL) { + return Pool; + } + + Pool->PciIo = PciIo; + Pool->Check4G = Check4G; + Pool->Which4G = Which4G; + Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES); + + if (Pool->Head == NULL) { + gBS->FreePool (Pool); + Pool = NULL; + } + + return Pool; +} + + +/** + Release the memory management pool. + + @param Pool The USB memory pool to free. + + @return EFI_SUCCESS The memory pool is freed. + @return EFI_DEVICE_ERROR Failed to free the memory pool. + +**/ +EFI_STATUS +UsbHcFreeMemPool ( + IN USBHC_MEM_POOL *Pool + ) +{ + USBHC_MEM_BLOCK *Block; + + ASSERT (Pool->Head != NULL); + + // + // Unlink all the memory blocks from the pool, then free them. + // UsbHcUnlinkMemBlock can't be used to unlink and free the + // first block. + // + for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) { + UsbHcUnlinkMemBlock (Pool->Head, Block); + UsbHcFreeMemBlock (Pool, Block); + } + + UsbHcFreeMemBlock (Pool, Pool->Head); + gBS->FreePool (Pool); + return EFI_SUCCESS; +} + + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +UsbHcAllocateMem ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + USBHC_MEM_BLOCK *NewBlock; + VOID *Mem; + UINTN AllocSize; + UINTN Pages; + + Mem = NULL; + AllocSize = USBHC_MEM_ROUND (Size); + Head = Pool->Head; + ASSERT (Head != NULL); + + // + // First check whether current memory blocks can satisfy the allocation. + // + for (Block = Head; Block != NULL; Block = Block->Next) { + Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + break; + } + } + + if (Mem != NULL) { + return Mem; + } + + // + // Create a new memory block if there is not enough memory + // in the pool. If the allocation size is larger than the + // default page number, just allocate a large enough memory + // block. Otherwise allocate default pages. + // + if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) { + Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1; + } else { + Pages = USBHC_MEM_DEFAULT_PAGES; + } + + NewBlock = UsbHcAllocMemBlock (Pool, Pages); + + if (NewBlock == NULL) { + DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n")); + return NULL; + } + + // + // Add the new memory block to the pool, then allocate memory from it + // + UsbHcInsertMemBlockToPool (Head, NewBlock); + Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + } + + return Mem; +} + + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +UsbHcFreeMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + UINT8 *ToFree; + UINTN AllocSize; + UINTN Byte; + UINTN Bit; + UINTN Count; + + Head = Pool->Head; + AllocSize = USBHC_MEM_ROUND (Size); + ToFree = (UINT8 *) Mem; + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the memory to free. + // + if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) { + // + // compute the start byte and bit in the bit array + // + Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8; + Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8; + + // + // reset associated bits in bit arry + // + for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) { + ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit)); + NEXT_BIT (Byte, Bit); + } + + break; + } + } + + // + // If Block == NULL, it means that the current memory isn't + // in the host controller's pool. This is critical because + // the caller has passed in a wrong memory point + // + ASSERT (Block != NULL); + + // + // Release the current memory block if it is empty and not the head + // + if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) { + UsbHcUnlinkMemBlock (Head, Block); + UsbHcFreeMemBlock (Pool, Block); + } + + return ; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/UsbHcMem.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/UsbHcMem.h new file mode 100644 index 000000000..5192abd2f --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/OhciDxe/UsbHcMem.h @@ -0,0 +1,161 @@ +/** @file + + This file contains the definination for host controller memory management routines + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_EHCI_MEM_H_ +#define _EFI_EHCI_MEM_H_ + +#define USB_HC_BIT(a) ((UINTN)(1 << (a))) + +#define USB_HC_BIT_IS_SET(Data, Bit) \ + ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit))) + +#define USB_HC_HIGH_32BIT(Addr64) \ + ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF)) + + +typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK; +struct _USBHC_MEM_BLOCK { + UINT8 *Bits; // Bit array to record which unit is allocated + UINTN BitsLen; + UINT8 *Buf; + UINT8 *BufHost; + UINTN BufLen; // Memory size in bytes + VOID *Mapping; + USBHC_MEM_BLOCK *Next; +}; + +// +// USBHC_MEM_POOL is used to manage the memory used by USB +// host controller. EHCI requires the control memory and transfer +// data to be on the same 4G memory. +// +typedef struct _USBHC_MEM_POOL { + EFI_PCI_IO_PROTOCOL *PciIo; + BOOLEAN Check4G; + UINT32 Which4G; + USBHC_MEM_BLOCK *Head; +} USBHC_MEM_POOL; + +// +// Memory allocation unit, must be 2^n, n>4 +// +#define USBHC_MEM_UNIT 64 + +#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1) +#define USBHC_MEM_DEFAULT_PAGES 16 + +#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK)) + +// +// Advance the byte and bit to the next bit, adjust byte accordingly. +// +#define NEXT_BIT(Byte, Bit) \ + do { \ + (Bit)++; \ + if ((Bit) > 7) { \ + (Byte)++; \ + (Bit) = 0; \ + } \ + } while (0) + + +/** + Initialize the memory management pool for the host controller. + + @param PciIo The PciIo that can be used to access the host controller. + @param Check4G Whether the host controller requires allocated memory + from one 4G address space. + @param Which4G The 4G memory area each memory allocated should be from. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool. + +**/ +USBHC_MEM_POOL * +UsbHcInitMemPool ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Check4G, + IN UINT32 Which4G + ); + + +/** + Release the memory management pool. + + @param Pool The USB memory pool to free. + + @return EFI_SUCCESS The memory pool is freed. + @return EFI_DEVICE_ERROR Failed to free the memory pool. + +**/ +EFI_STATUS +UsbHcFreeMemPool ( + IN USBHC_MEM_POOL *Pool + ); + + + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +UsbHcAllocateMem ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Size + ); + + + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + + @return None. + +**/ +VOID +UsbHcFreeMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +/** + Calculate the corresponding pci bus address according to the Mem parameter. + + @param Pool The memory pool of the host controller. + @param Mem The pointer to host memory. + @param Size The size of the memory region. + + @return the pci memory address +**/ +EFI_PHYSICAL_ADDRESS +UsbHcGetPciAddressForHostMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB.c new file mode 100644 index 000000000..e89ba4b0a --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB.c @@ -0,0 +1,353 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Uefi.h> +#include <Exynos5_USB2Phy.h> +#include <Exynos5_USB3Phy.h> +#include <Exynos5_USB3Drd.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Protocol/ExynosGpio.h> +#include <Platform/ArmPlatform.h> + +#define PHY_ENABLE (1 << 0) +#define PHY_DISABLE (0) + +enum usb_phy_type { + USB_PHY = (0x1 << 0), + USB_PHY0 = (0x1 << 0), + USB_PHY1 = (0x1 << 1), + USB_PHY_HSIC0 = (0x1 << 1), + USB_PHY_HSIC1 = (0x1 << 2), +}; + + +static void usb_clk_get(enum usb_clk_type clk_type) +{ + if( clk_type == USBOTG_CLK) { + MmioWrite32(CLK_GATE_IP_FSYS, MmioRead32(CLK_GATE_IP_FSYS) | (1<<7)); + } else if( clk_type == USBHOST_CLK) { + MmioWrite32(CLK_GATE_IP_FSYS, MmioRead32(CLK_GATE_IP_FSYS) | (1<<18)); + } else if( clk_type == USBDRD30_CLK) { + MmioWrite32(CLK_GATE_IP_FSYS, MmioRead32(CLK_GATE_IP_FSYS) | (1<<19)); + } else { + DEBUG ((EFI_D_ERROR, "FAIL! usb_clk_get\n")); + } + + return; +} + +static void usb_clk_put(enum usb_clk_type clk_type) +{ + if( clk_type == USBOTG_CLK) { + MmioWrite32(CLK_GATE_IP_FSYS, MmioRead32(CLK_GATE_IP_FSYS) & ~ (1<<7)); + } else if( clk_type == USBHOST_CLK) { + MmioWrite32(CLK_GATE_IP_FSYS, MmioRead32(CLK_GATE_IP_FSYS) & ~ (1<<18)); + } else if( clk_type == USBDRD30_CLK) { + MmioWrite32(CLK_GATE_IP_FSYS, MmioRead32(CLK_GATE_IP_FSYS) & ~ (1<<19)); + } else { + DEBUG ((EFI_D_ERROR, "FAIL! usb_clk_get\n")); + } + + return; +} + +//------------------------------------------------------------------------------------ + +////////// +// Function Name : USBPHY_Ctr48MhzClk +// Function Desctiption : This function sets clk48m_ohci in Suspend Mode. +// Input : NONE +// Output : NONE +// Version : +void USBPHY_Ctr48MhzClk(UINT8 bEnable_48Mhz) +{ + + UINT32 uTemp; + + uTemp = MmioRead32(rUPHY_OHCICTRL); + uTemp &= ~(1<<2); + uTemp |= bEnable_48Mhz<<2; + MmioWrite32(rUPHY_OHCICTRL, uTemp); +} + +static int exynos5_usb_host_phy20_is_on(void) +{ + return (MmioRead32(EXYNOS5_USB2_PHY_HOST_CTRL0) & HOST_CTRL0_PHYSWRSTALL) ? 0 : 1; +} + +static void exynos5_usb_phy_control(enum usb_phy_type phy_type , int on) +{ + if (phy_type & USB_PHY0) + MmioWrite32(EXYNOS5_USBDEV_PHY_CONTROL, on); + if (phy_type & USB_PHY1) + MmioWrite32(EXYNOS5_USBHOST_PHY_CONTROL, on); +} + +void exynos5_usb_phy20_init(void) +{ + EFI_STATUS Status; + EXYNOS_GPIO *Gpio; + UINT32 hostphy_ctrl0; + UINT32 hsic_ctrl; + UINT32 ehcictrl; + + DEBUG ((EFI_D_ERROR, "exynos5_usb_phy20_init START $$$\n")); + + Status = gBS->LocateProtocol(&gSamsungPlatformGpioProtocolGuid, NULL, (VOID **)&Gpio); + ASSERT_EFI_ERROR(Status); + + if(PcdGetBool(PcdExynos5250Evt1)) + { + Gpio->Set(Gpio, USB_2_EVT1, GPIO_MODE_OUTPUT_1); + Gpio->SetPull(Gpio, USB_2_EVT1, GPIO_PULL_NONE); + } + + if (exynos5_usb_host_phy20_is_on()) + { + DEBUG ((EFI_D_ERROR, "Already power on PHY $$$\n")); + return; + } + + // Must be enable usbhost & usbotg clk + usb_clk_get(USBHOST_CLK); + usb_clk_get(USBOTG_CLK); + + MmioWrite32(ETC6PUD, (MmioRead32(ETC6PUD) & ~(0x3 << 14)) | (0x3 << 14)); + + exynos5_usb_phy_control(USB_PHY1, PHY_ENABLE); + + /* Host and Device should be set at the same time */ + hostphy_ctrl0 = MmioRead32(EXYNOS5_USB2_PHY_HOST_CTRL0); + hostphy_ctrl0 &= ~(HOST_CTRL0_FSEL_MASK); + + /* 2.0 phy reference clock configuration */ + // default reference clock 24MZ + hostphy_ctrl0 |= CLKSEL_24M; + + /* COMMON Block configuration during suspend */ + hostphy_ctrl0 &= ~(HOST_CTRL0_COMMONONN); + + /* host phy reset */ + hostphy_ctrl0 &= ~(HOST_CTRL0_PHYSWRST | HOST_CTRL0_PHYSWRSTALL | HOST_CTRL0_SIDDQ); + hostphy_ctrl0 &= ~(HOST_CTRL0_FORCESUSPEND | HOST_CTRL0_FORCESLEEP); + hostphy_ctrl0 |= (HOST_CTRL0_LINKSWRST | HOST_CTRL0_UTMISWRST); + MmioWrite32(EXYNOS5_USB2_PHY_HOST_CTRL0, hostphy_ctrl0); + MicroSecondDelay(10); + MicroSecondDelay(10); + hostphy_ctrl0 &= ~(HOST_CTRL0_LINKSWRST | HOST_CTRL0_UTMISWRST); + MmioWrite32(EXYNOS5_USB2_PHY_HOST_CTRL0, hostphy_ctrl0); + + DEBUG ((EFI_D_ERROR, "exynos5_usb_phy20_init Clk set $$$\n")); + + /* HSIC phy reset */ + hsic_ctrl = (HSIC_CTRL_REFCLKDIV(0x24) | HSIC_CTRL_REFCLKSEL(0x2) |HSIC_CTRL_PHYSWRST); + MmioWrite32(PHY_HSIC_CTRL1, hsic_ctrl); + MmioWrite32(PHY_HSIC_CTRL2, hsic_ctrl); + MicroSecondDelay(10); + MicroSecondDelay(10); + hsic_ctrl = (HSIC_CTRL_REFCLKDIV(0x24) | HSIC_CTRL_REFCLKSEL(0x2)); + MmioWrite32(PHY_HSIC_CTRL1, hsic_ctrl); + MmioWrite32(PHY_HSIC_CTRL2, hsic_ctrl); + + MicroSecondDelay(80); + MicroSecondDelay(80); + + /* enable EHCI DMA burst */ + ehcictrl = MmioRead32(PHY_HOST_EHCICTRL); + ehcictrl |= (EHCICTRL_ENAINCRXALIGN | EHCICTRL_ENAINCR4 |EHCICTRL_ENAINCR8 | EHCICTRL_ENAINCR16); + MmioWrite32(PHY_HOST_EHCICTRL, ehcictrl); + + DEBUG ((EFI_D_ERROR, "exynos5_usb_phy20_init END $$$\n")); +} + +void exynos5_usb_phy20_off(void) +{ + UINT32 uTemp; + + uTemp = MmioRead32(rUPHY_USBCTRL0); + uTemp |= (0x1<<9); + MmioWrite32(rUPHY_USBCTRL0, uTemp); + + usb_clk_put(USBOTG_CLK); + usb_clk_put(USBHOST_CLK); +} + + +void exynos5_usb_phy30_init(void) +{ + UINT32 reg; + DEBUG ((EFI_D_ERROR, "exynos5_usb_phy30_init START $$$\n")); + + MmioWrite32(0x10020548, 0x0BF00000); + usb_clk_get(USBDRD30_CLK); + + exynos5_usb_phy_control(USB_PHY0, PHY_ENABLE); + + /* Reset USB 3.0 PHY */ + MmioWrite32(EXYNOS_USB3_PHYREG0, 0x00000000); + MmioWrite32(EXYNOS_USB3_PHYPARAM0, 0x24d4e6e4); + MmioWrite32(EXYNOS_USB3_PHYRESUME, 0x00000000); + + if(PcdGetBool(PcdExynos5250Evt1)) + { + MmioWrite32(EXYNOS_USB3_LINKSYSTEM, 0x08000000); + MmioWrite32(EXYNOS_USB3_PHYPARAM1, 0x03fff81C); + MmioWrite32(EXYNOS_USB3_PHYBATCHG, 0x00000004); + } else { + MmioWrite32(EXYNOS_USB3_LINKSYSTEM, 0x087FFFC0); + MmioWrite32(EXYNOS_USB3_PHYPARAM1, 0x03fff820); + MmioWrite32(EXYNOS_USB3_PHYBATCHG, 0x00000000); + MmioWrite32(EXYNOS_USB3_LINKPORT, (MmioRead32(EXYNOS_USB3_LINKPORT) & ~(0x3<<4)) |(0x3<<2)); + } + + /* UTMI Power Control */ + MmioWrite32(EXYNOS_USB3_PHYUTMI, EXYNOS_USB3_PHYUTMI_OTGDISABLE); + + if(PcdGetBool(PcdExynos5250Evt1)) + { + /* Set 100MHz external clock */ + reg = EXYNOS_USB3_PHYCLKRST_PORTRESET | + /* HS PLL uses ref_pad_clk{p,m} or ref_alt_clk_{p,m} + * as reference */ + EXYNOS_USB3_PHYCLKRST_REFCLKSEL(3) | + /* Digital power supply in normal operating mode */ + EXYNOS_USB3_PHYCLKRST_RETENABLEN | + /* 0x27-100MHz, 0x2a-24MHz, 0x31-20MHz, 0x38-19.2MHz */ + EXYNOS_USB3_PHYCLKRST_FSEL(0x5) | + /* 0x19-100MHz, 0x68-24MHz, 0x7d-20Mhz */ + EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER(0x68) | + EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL(0x88) | + /* Enable ref clock for SS function */ + EXYNOS_USB3_PHYCLKRST_REF_SSP_EN | + /* Enable spread spectrum */ + EXYNOS_USB3_PHYCLKRST_SSC_EN; + } else { + /* Set 100MHz external clock */ + reg = EXYNOS_USB3_PHYCLKRST_PORTRESET | + /* HS PLL uses ref_pad_clk{p,m} or ref_alt_clk_{p,m} + * as reference */ + EXYNOS_USB3_PHYCLKRST_REFCLKSEL(2) | + /* Digital power supply in normal operating mode */ + EXYNOS_USB3_PHYCLKRST_RETENABLEN | + /* 0x27-100MHz, 0x2a-24MHz, 0x31-20MHz, 0x38-19.2MHz */ + EXYNOS_USB3_PHYCLKRST_FSEL(0x27) | + /* 0x19-100MHz, 0x68-24MHz, 0x7d-20Mhz */ + EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER(0x19) | + EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL(0x00) | + /* Enable ref clock for SS function */ + EXYNOS_USB3_PHYCLKRST_REF_SSP_EN | + /* Enable spread spectrum */ + EXYNOS_USB3_PHYCLKRST_SSC_EN | + EXYNOS_USB3_PHYCLKRST_COMMONONN; + } + MmioWrite32(EXYNOS_USB3_PHYCLKRST, reg); + + MicroSecondDelay(10); + MicroSecondDelay(10); + + reg &= ~(EXYNOS_USB3_PHYCLKRST_PORTRESET); + + MmioWrite32(EXYNOS_USB3_PHYCLKRST, reg); + DEBUG ((EFI_D_ERROR, "exynos5_usb_phy30_init END $$$\n")); + +} + +void exynos_xhci_phy_set(void) +{ + /* The reset values: + * GUSB2PHYCFG(0) = 0x00002400 + * GUSB3PIPECTL(0) = 0x00260002 + */ + // orr32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GCTL, + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GCTL) | EXYNOS_USB3_GCTL_CoreSoftReset)); + // orr32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0), + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0)) | EXYNOS_USB3_GUSB2PHYCFGx_PHYSoftRst)); + // orr32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB3PIPECTL(0), + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB3PIPECTL(0)) | EXYNOS_USB3_GUSB3PIPECTLx_PHYSoftRst)); + + exynos5_usb_phy30_init(); + + // bic32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0), + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0)) & ~EXYNOS_USB3_GUSB2PHYCFGx_PHYSoftRst)); + // bic32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB3PIPECTL(0), + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB3PIPECTL(0)) & ~EXYNOS_USB3_GUSB3PIPECTLx_PHYSoftRst)); + // bic32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GCTL, + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GCTL) & ~EXYNOS_USB3_GCTL_CoreSoftReset)); + // bic32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0), + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0)) & ~(EXYNOS_USB3_GUSB2PHYCFGx_SusPHY | + EXYNOS_USB3_GUSB2PHYCFGx_EnblSlpM | + EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_MASK))); + + // orr32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0), + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0)) | EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim(9))); + + // bic32 + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB3PIPECTL(0), + (MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB3PIPECTL(0)) & ~EXYNOS_USB3_GUSB3PIPECTLx_SuspSSPhy)); + + + DEBUG ((EFI_D_ERROR, "GUSB2PHYCFG(0)=0x%08x, GUSB3PIPECTL(0)=0x%08x\n", + MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB2PHYCFG(0)), + MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GUSB3PIPECTL(0)))); + + /* Global core init */ + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GSBUSCFG0, + EXYNOS_USB3_GSBUSCFG0_INCR16BrstEna | + EXYNOS_USB3_GSBUSCFG0_INCR8BrstEna | + EXYNOS_USB3_GSBUSCFG0_INCR4BrstEna); + + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GSBUSCFG1, + EXYNOS_USB3_GSBUSCFG1_BREQLIMIT(0x3)); + + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GTXTHRCFG, 0x0); + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GRXTHRCFG, 0x0); +} + +UINT32 exynos_xhci_change_mode(void) +{ + UINT32 gctl; + + gctl = MmioRead32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GCTL); + gctl &= ~(EXYNOS_USB3_GCTL_PrtCapDir_MASK | + EXYNOS_USB3_GCTL_FRMSCLDWN_MASK | + EXYNOS_USB3_GCTL_RAMClkSel_MASK); + + gctl |= (EXYNOS_USB3_GCTL_FRMSCLDWN(0x1e85) | /* Power Down Scale */ + EXYNOS_USB3_GCTL_RAMClkSel(0x2) | /* Ram Clock Select */ + EXYNOS_USB3_GCTL_DisScramble); + + gctl |= EXYNOS_USB3_GCTL_PrtCapDir(0x1);/* 0x1 : Host */ + + MmioWrite32(EXYNOS5_USB3_DRD_BASEADDR + EXYNOS_USB3_GCTL, gctl); + + DEBUG ((EFI_D_ERROR, "Change xHCI host mode %x\n", gctl)); + return gctl; +} + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB2Phy.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB2Phy.h new file mode 100644 index 000000000..fce6ca830 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB2Phy.h @@ -0,0 +1,114 @@ +#ifndef _EFI_EXYNOS5_USB2_PHY_H_ +#define _EFI_EXYNOS5_USB2_PHY_H_ + +#define USB_XHCI_HCCAPBASE (0x12000000) //Gaia +#define USB_EHCI_HCCAPBASE (0x12110000) //Gaia +#define USB_OHCI_HCCAPBASE (USB_EHCI_HCCAPBASE + 0x10000) + +#define EXYNOS5_USB2_PHY_HOST_CTRL0 0x12130000 //Gaia + +#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31) +#define CLKSEL_50M (0x7 << 16) +#define CLKSEL_24M (0x5 << 16) +#define CLKSEL_20M (0x4 << 16) +#define CLKSEL_19200K (0x3 << 16) +#define CLKSEL_12M (0x2 << 16) +#define CLKSEL_10M (0x1 << 16) +#define CLKSEL_9600K (0x0 << 16) +#define HOST_CTRL0_FSEL_MASK (0x7 << 16) +#define HOST_CTRL0_COMMONONN (0x1 << 9) +#define HOST_CTRL0_PHYSWRST (0x1 << 0) +#define HOST_CTRL0_SIDDQ (0x1 << 6) +#define HOST_CTRL0_FORCESLEEP (0x1 << 5) +#define HOST_CTRL0_FORCESUSPEND (0x1 << 4) +#define HOST_CTRL0_LINKSWRST (0x1 << 1) +#define HOST_CTRL0_UTMISWRST (0x1 << 2) +#define HSIC_CTRL_REFCLKDIV(val) ((val&0x7f) << 16) +#define HSIC_CTRL_REFCLKSEL(val) ((val&0x3) << 23) +#define HSIC_CTRL_PHYSWRST (0x1 << 0) +#define PHY_HSIC_CTRL1 (EXYNOS5_USB2_PHY_HOST_CTRL0 + 0x10) +#define PHY_HSIC_CTRL2 (EXYNOS5_USB2_PHY_HOST_CTRL0 + 0x20) +#define PHY_HOST_EHCICTRL (EXYNOS5_USB2_PHY_HOST_CTRL0 + 0x30) +#define EHCICTRL_ENAINCRXALIGN (0x1 << 29) +#define EHCICTRL_ENAINCR4 (0x1 << 28) +#define EHCICTRL_ENAINCR8 (0x1 << 27) +#define EHCICTRL_ENAINCR16 (0x1 << 26) + +//CMU +#define CLK_GATE_IP_FSYS 0x10020944 //GAIA + +//GPIO +#define ETC6PUD (0x114002A8) //(0x11400000 + 0x2A8) + +//PMU +#define EXYNOS5_USBDEV_PHY_CONTROL (0x10040000 + 0x0704) +#define EXYNOS5_USBHOST_PHY_CONTROL (0x10040000 + 0x0708) + + +//--------------------- for gaia ---------- +#define UHOST_FIN 48000000 +#define USBDEV_FIN 12000000 + +#define USBHOST_AHB_INCR16 0x2000000 +#define USBHOST_AHB_INCR8 0x1000000 +#define USBHOST_AHB_INCR4 0x0800000 +#define USBHOST_AHB_INCRs 0x3800000 +#define USBHOST_AHB_INCRx 0x3c00000 +#define USBHOST_AHB_SINGLE 0x0000000 + +typedef enum +{ + REFCLK_XTAL = 0x0, //XO : form Crystal + REFCLK_OSC = 0x1, //XO : OSC 1.8V Clock + REFCLK_PLL = 0x2, //PLL form CLKCORE +}USBPHY_REFCLK; + +typedef enum +{ + FSEL_9_6M = 0x0, + FSEL_10M = 0x1, + FSEL_12M = 0x2, + FSEL_19_2M = 0x3, + FSEL_20M = 0x4, + FSEL_24M = 0x5, + FSEL_48M = 0x6, //Reserved + FSEL_50M = 0x7, +}USBPHY_REFSEL; + +#define USBPHY_RETENABLE 1 //Retention Mode Enable == 1, Normal Operation mode must be 1. + +void USBPHY_Ctr48MhzClk(UINT8 bEnable_48Mhz); +void usb_host_phy_off(void); + +//------------------------------------------------------- +//OTG + +enum USBPHY_CON_SFR +{ + rUPHY_USBCTRL0 = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0000, + rUPHY_USBTUNE0 = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0004, + rUPHY_HSICCTRL1 = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0010, + rUPHY_HSICTUNE1 = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0014, + rUPHY_HSICCTRL2 = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0020, + rUPHY_HSICTUNE2 = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0024, + + rUPHY_EHCICTRL = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0030, + rUPHY_OHCICTRL = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0034, + + rUPHY_USBOTG_SYS = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0038, + rUPHY_USBOTG_TUNE = EXYNOS5_USB2_PHY_HOST_CTRL0+0x0040, +}; + +enum usb_clk_type { + USBOTG_CLK, USBHOST_CLK, USBDRD30_CLK +}; + +//------------------------------------------------------- +// Functions +//------------------------------------------------------- + +void exynos5_usb_phy20_init(void); + +#endif + + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB3Drd.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB3Drd.h new file mode 100644 index 000000000..09b66e1d5 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB3Drd.h @@ -0,0 +1,403 @@ +/* include/linux/usb/exynos_usb3_drd.h + * + * Copyright (c) 2012 Samsung Electronics Co. Ltd + * Author: Anton Tikhomirov <av.tikhomirov@samsung.com> + * + * Exynos SuperSpeed USB 3.0 DRD Controller global and OTG registers + * + * 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. + */ + +#ifndef __LINUX_USB_EXYNOS_USB3_DRD_H +#define __LINUX_USB_EXYNOS_USB3_DRD_H + +#define EXYNOS5_USB3_DRD_BASEADDR 0x12000000 + +/* Global registers */ +#define EXYNOS_USB3_GSBUSCFG0 0xC100 +#define EXYNOS_USB3_GSBUSCFG0_SBusStoreAndForward (1 << 12) +#define EXYNOS_USB3_GSBUSCFG0_DatBigEnd (1 << 11) +#define EXYNOS_USB3_GSBUSCFG0_INCR256BrstEna (1 << 7) +#define EXYNOS_USB3_GSBUSCFG0_INCR128BrstEna (1 << 6) +#define EXYNOS_USB3_GSBUSCFG0_INCR64BrstEna (1 << 5) +#define EXYNOS_USB3_GSBUSCFG0_INCR32BrstEna (1 << 4) +#define EXYNOS_USB3_GSBUSCFG0_INCR16BrstEna (1 << 3) +#define EXYNOS_USB3_GSBUSCFG0_INCR8BrstEna (1 << 2) +#define EXYNOS_USB3_GSBUSCFG0_INCR4BrstEna (1 << 1) +#define EXYNOS_USB3_GSBUSCFG0_INCRBrstEna (1 << 0) + +#define EXYNOS_USB3_GSBUSCFG1 0xC104 +#define EXYNOS_USB3_GSBUSCFG1_EN1KPAGE (1 << 12) +#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT_MASK (0xf << 8) +#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT_SHIFT 8 +#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT(_x) ((_x) << 8) + +#define EXYNOS_USB3_GTXTHRCFG 0xC108 +#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCntSel (1 << 29) +#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt_MASK (0xf << 24) +#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt_SHIFT 24 +#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt(_x) ((_x) << 24) +#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize_MASK (0xff << 16) +#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize_SHIFT 16 +#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize(_x) ((_x) << 16) + +#define EXYNOS_USB3_GRXTHRCFG 0xC10C +#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCntSel (1 << 29) +#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt_MASK (0xf << 24) +#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt_SHIFT 24 +#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt(_x) ((_x) << 24) +#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize_MASK (0x1f << 19) +#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize_SHIFT 19 +#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize(_x) ((_x) << 19) + +#define EXYNOS_USB3_GCTL 0xC110 +#define EXYNOS_USB3_GCTL_PwrDnScale_MASK (0x1fff << 19) +#define EXYNOS_USB3_GCTL_PwrDnScale_SHIFT 19 +#define EXYNOS_USB3_GCTL_PwrDnScale(_x) ((_x) << 19) +#define EXYNOS_USB3_GCTL_U2RSTECN (1 << 16) +#define EXYNOS_USB3_GCTL_FRMSCLDWN_MASK (0x3 << 14) +#define EXYNOS_USB3_GCTL_FRMSCLDWN_SHIFT 14 +#define EXYNOS_USB3_GCTL_FRMSCLDWN(_x) ((_x) << 14) +#define EXYNOS_USB3_GCTL_PrtCapDir_MASK (0x3 << 12) +#define EXYNOS_USB3_GCTL_PrtCapDir_SHIFT 12 +#define EXYNOS_USB3_GCTL_PrtCapDir(_x) ((_x) << 12) +#define EXYNOS_USB3_GCTL_CoreSoftReset (1 << 11) +#define EXYNOS_USB3_GCTL_LocalLpBkEn (1 << 10) +#define EXYNOS_USB3_GCTL_LpbkEn (1 << 9) +#define EXYNOS_USB3_GCTL_DebugAttach (1 << 8) +#define EXYNOS_USB3_GCTL_RAMClkSel_MASK (0x3 << 6) +#define EXYNOS_USB3_GCTL_RAMClkSel_SHIFT 6 +#define EXYNOS_USB3_GCTL_RAMClkSel(_x) ((_x) << 6) +#define EXYNOS_USB3_GCTL_ScaleDown_MASK (0x3 << 4) +#define EXYNOS_USB3_GCTL_ScaleDown_SHIFT 4 +#define EXYNOS_USB3_GCTL_ScaleDown(_x) ((_x) << 4) +#define EXYNOS_USB3_GCTL_DisScramble (1 << 3) +#define EXYNOS_USB3_GCTL_SsPwrClmp (1 << 2) +#define EXYNOS_USB3_GCTL_HsFsLsPwrClmp (1 << 1) +#define EXYNOS_USB3_GCTL_DsblClkGtng (1 << 0) + +#define EXYNOS_USB3_GEVTEN 0xC114 +#define EXYNOS_USB3_GEVTEN_I2CEvtEn (1 << 1) +#define EXYNOS_USB3_GEVTEN_ULPICKEvtEn (1 << 0) +#define EXYNOS_USB3_GEVTEN_I2CCKEvtEn (1 << 0) + +#define EXYNOS_USB3_GSTS 0xC118 +#define EXYNOS_USB3_GSTS_CBELT_MASK (0xfff << 20) +#define EXYNOS_USB3_GSTS_CBELT_SHIFT 20 +#define EXYNOS_USB3_GSTS_CBELT(_x) ((_x) << 20) +#define EXYNOS_USB3_GSTS_OTG_IP (1 << 10) +#define EXYNOS_USB3_GSTS_BC_IP (1 << 9) +#define EXYNOS_USB3_GSTS_ADP_IP (1 << 8) +#define EXYNOS_USB3_GSTS_Host_IP (1 << 7) +#define EXYNOS_USB3_GSTS_Device_IP (1 << 6) +#define EXYNOS_USB3_GSTS_CSRTimeout (1 << 5) +#define EXYNOS_USB3_GSTS_BusErrAddrVld (1 << 4) +#define EXYNOS_USB3_GSTS_CurMod_MASK (0x3 << 0) +#define EXYNOS_USB3_GSTS_CurMod_SHIFT 0 +#define EXYNOS_USB3_GSTS_CurMod(_x) ((_x) << 0) + +#define EXYNOS_USB3_GSNPSID 0xC120 + +#define EXYNOS_USB3_GGPIO 0xC124 +#define EXYNOS_USB3_GGPIO_GPO_MASK (0xffff << 16) +#define EXYNOS_USB3_GGPIO_GPO_SHIFT 16 +#define EXYNOS_USB3_GGPIO_GPO(_x) ((_x) << 16) +#define EXYNOS_USB3_GGPIO_GPI_MASK (0xffff << 0) +#define EXYNOS_USB3_GGPIO_GPI_SHIFT 0 +#define EXYNOS_USB3_GGPIO_GPI(_x) ((x) << 0) + +#define EXYNOS_USB3_GUID 0xC128 + +#define EXYNOS_USB3_GUCTL 0xC12C +#define EXYNOS_USB3_GUCTL_SprsCtrlTransEn (1 << 17) +#define EXYNOS_USB3_GUCTL_ResBwHSEPS (1 << 16) +#define EXYNOS_USB3_GUCTL_CMdevAddr (1 << 15) +#define EXYNOS_USB3_GUCTL_USBHstInAutoRetryEn (1 << 14) +#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst_MASK (0x7 << 11) +#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst_SHIFT 11 +#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst(_x) ((_x) << 11) +#define EXYNOS_USB3_GUCTL_DTCT_MASK (0x3 << 9) +#define EXYNOS_USB3_GUCTL_DTCT_SHIFT 9 +#define EXYNOS_USB3_GUCTL_DTCT(_x) ((_x) << 9) +#define EXYNOS_USB3_GUCTL_DTFT_MASK (0x1ff << 0) +#define EXYNOS_USB3_GUCTL_DTFT_SHIFT 0 +#define EXYNOS_USB3_GUCTL_DTFT(_x) ((_x) << 0) + +#define EXYNOS_USB3_GBUSERRADDR_31_0 0xC130 +#define EXYNOS_USB3_GBUSERRADDR_63_32 0xC134 +#define EXYNOS_USB3_GPRTBIMAP_31_0 0xC138 +#define EXYNOS_USB3_GPRTBIMAP_63_32 0xC13C + +#define EXYNOS_USB3_GHWPARAMS0 0xC140 +#define EXYNOS_USB3_GHWPARAMS1 0xC144 +#define EXYNOS_USB3_GHWPARAMS2 0xC148 +#define EXYNOS_USB3_GHWPARAMS3 0xC14C +#define EXYNOS_USB3_GHWPARAMS4 0xC150 +#define EXYNOS_USB3_GHWPARAMS5 0xC154 +#define EXYNOS_USB3_GHWPARAMS6 0xC158 +#define EXYNOS_USB3_GHWPARAMS7 0xC15C + +#define EXYNOS_USB3_GDBGFIFOSPACE 0xC160 +#define EXYNOS_USB3_GDBGLTSSM 0xC164 + +#define EXYNOS_USB3_GDBGLSPMUX 0xC170 +#define EXYNOS_USB3_GDBGLSP 0xC174 +#define EXYNOS_USB3_GDBGEPINFO0 0xC178 +#define EXYNOS_USB3_GDBGEPINFO1 0xC17C + +#define EXYNOS_USB3_GPRTBIMAP_HS_31_0 0xC180 +#define EXYNOS_USB3_GPRTBIMAP_HS_63_32 0xC184 +#define EXYNOS_USB3_GPRTBIMAP_FS_31_0 0xC188 +#define EXYNOS_USB3_GPRTBIMAP_FS_63_32 0xC18C + +#define EXYNOS_USB3_GUSB2PHYCFG(_a) (0xC200 + ((_a) * 0x04)) +#define EXYNOS_USB3_GUSB2PHYCFGx_PHYSoftRst (1 << 31) +#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum_MASK (0x3f << 19) +#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum_SHIFT 19 +#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum(_x) ((_x) << 19) +#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIExtVbusIndicator (1 << 18) +#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIExtVbusDrv (1 << 17) +#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIClkSusM (1 << 16) +#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIAutoRes (1 << 15) +#define EXYNOS_USB3_GUSB2PHYCFGx_PhyLPwrClkSel (1 << 14) +#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_MASK (0xf << 10) +#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_SHIFT 10 +#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim(_x) ((_x) << 10) +#define EXYNOS_USB3_GUSB2PHYCFGx_EnblSlpM (1 << 8) +#define EXYNOS_USB3_GUSB2PHYCFGx_PHYSel (1 << 7) +#define EXYNOS_USB3_GUSB2PHYCFGx_SusPHY (1 << 6) +#define EXYNOS_USB3_GUSB2PHYCFGx_FSIntf (1 << 5) +#define EXYNOS_USB3_GUSB2PHYCFGx_ULPI_UTMI_Sel (1 << 4) +#define EXYNOS_USB3_GUSB2PHYCFGx_PHYIf (1 << 3) +#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal_MASK (0x7 << 0) +#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal_SHIFT 0 +#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal(_x) ((_x) << 0) + +#define EXYNOS_USB3_GUSB2I2CCTL(_a) (0xC240 + ((_a) * 0x04)) + +#define EXYNOS_USB3_GUSB2PHYACC(_a) (0xC280 + ((_a) * 0x04)) +#define EXYNOS_USB3_GUSB2PHYACCx_DisUlpiDrvr (1 << 26) +#define EXYNOS_USB3_GUSB2PHYACCx_NewRegReq (1 << 25) +#define EXYNOS_USB3_GUSB2PHYACCx_VStsDone (1 << 24) +#define EXYNOS_USB3_GUSB2PHYACCx_VStsBsy (1 << 23) +#define EXYNOS_USB3_GUSB2PHYACCx_RegWr (1 << 22) +#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr_MASK (0x3f << 16) +#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr_SHIFT 16 +#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr(_x) ((_x) << 16) +/* Next 2 fields are overlaping. Is it error in user manual? */ +#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl_MASK (0xff << 8) +#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl_SHIFT 8 +#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl(_x) ((_x) << 8) +/*--------*/ +#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr_MASK (0x3f << 8) +#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr_SHIFT 8 +#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr(_x) ((_x) << 8) +/*--------*/ +#define EXYNOS_USB3_GUSB2PHYACCx_RegData_MASK (0xff << 0) +#define EXYNOS_USB3_GUSB2PHYACCx_RegData_SHIFT 0 +#define EXYNOS_USB3_GUSB2PHYACCx_RegData(_x) ((_x) << 0) + +#define EXYNOS_USB3_GUSB3PIPECTL(_a) (0xC2C0 + ((_a) * 0x04)) +#define EXYNOS_USB3_GUSB3PIPECTLx_PHYSoftRst (1 << 31) +#define EXYNOS_USB3_GUSB3PIPECTLx_request_p1p2p3 (1 << 24) +#define EXYNOS_USB3_GUSB3PIPECTLx_StartRxdetU3RxDet (1 << 23) +#define EXYNOS_USB3_GUSB3PIPECTLx_DisRxDetU3RxDet (1 << 22) +#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3_MASK (0x7 << 19) +#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3_SHIFT 19 +#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3(_x) ((_x) << 19) +#define EXYNOS_USB3_GUSB3PIPECTLx_delay_phy_pwr_p1p2p3 (1 << 18) +#define EXYNOS_USB3_GUSB3PIPECTLx_SuspSSPhy (1 << 17) +#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth_MASK (0x3 << 15) +#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth_SHIFT 15 +#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth(_x) ((_x) << 15) +#define EXYNOS_USB3_GUSB3PIPECTLx_AbortRxDetInU2 (1 << 14) +#define EXYNOS_USB3_GUSB3PIPECTLx_SkipRxDet (1 << 13) +#define EXYNOS_USB3_GUSB3PIPECTLx_LFPSP0Algn (1 << 12) +#define EXYNOS_USB3_GUSB3PIPECTLx_P3P2TranOK (1 << 11) +#define EXYNOS_USB3_GUSB3PIPECTLx_LFPSFilt (1 << 9) +#define EXYNOS_USB3_GUSB3PIPECTLx_TxSwing (1 << 6) +#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin_MASK (0x7 << 3) +#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin_SHIFT 3 +#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin(_x) ((_x) << 3) +#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis_MASK (0x3 << 1) +#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis_SHIFT 1 +#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis(_x) ((_x) << 1) +#define EXYNOS_USB3_GUSB3PIPECTLx_ElasticBufferMode (1 << 0) + +#define EXYNOS_USB3_GTXFIFOSIZ(_a) (0xC300 + ((_a) * 0x04)) +#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n_MASK (0xffff << 16) +#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n_SHIFT 16 +#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n(_x) ((_x) << 16) +#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n_MASK (0xffff << 0) +#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n_SHIFT 0 +#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n(_x) ((_x) << 0) + +#define EXYNOS_USB3_GRXFIFOSIZ(_a) (0xC380 + ((_a) * 0x04)) +#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n_MASK (0xffff << 16) +#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n_SHIFT 16 +#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n(_x) ((_x) << 16) +#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n_MASK (0xffff << 0) +#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n_SHIFT 0 +#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n(_x) ((_x) << 0) + +#define EXYNOS_USB3_GEVNTADR_31_0(_a) (0xC400 + ((_a) * 0x10)) +#define EXYNOS_USB3_GEVNTADR_63_32(_a) (0xC404 + ((_a) * 0x10)) + +#define EXYNOS_USB3_GEVNTSIZ(_a) (0xC408 + ((_a) * 0x10)) +#define EXYNOS_USB3_GEVNTSIZx_EvntIntMask (1 << 31) +#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz_MASK (0xffff << 0) +#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz_SHIFT 0 +#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz(x) ((_x) << 0) + +#define EXYNOS_USB3_GEVNTCOUNT(_a) (0xC40C + ((_a) * 0x10)) +#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_MASK (0xffff << 0) +#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_SHIFT 0 +#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount(_x) ((_x) << 0) + +/* Event Buffer Content for Device Endpoint-Specific Events (DEPEVT) */ +#define EXYNOS_USB3_DEPEVT_EventParam_MASK (0xffff << 16) +#define EXYNOS_USB3_DEPEVT_EventParam_SHIFT 16 +#define EXYNOS_USB3_DEPEVT_EventParam(_x) ((_x) << 16) +#define EXYNOS_USB3_DEPEVT_EventStatus_MASK (0xf << 12) +#define EXYNOS_USB3_DEPEVT_EventStatus_SHIFT 12 +#define EXYNOS_USB3_DEPEVT_EventStatus_CTL_MASK (0x3 << 12) +#define EXYNOS_USB3_DEPEVT_EventStatus_CTL_SETUP (0 << 12) +#define EXYNOS_USB3_DEPEVT_EventStatus_CTL_DATA (1 << 12) +#define EXYNOS_USB3_DEPEVT_EventStatus_CTL_STATUS (2 << 12) +#define EXYNOS_USB3_DEPEVT_EventStatus_BUSERR (1 << 12) +#define EXYNOS_USB3_DEPEVT_EVENT_MASK (0xf << 6) +#define EXYNOS_USB3_DEPEVT_EVENT_SHIFT 6 +#define EXYNOS_USB3_DEPEVT_EVENT_EPCmdCmplt (7 << 6) +#define EXYNOS_USB3_DEPEVT_EVENT_StreamEvt (6 << 6) +#define EXYNOS_USB3_DEPEVT_EVENT_RxTxfifoEvt (4 << 6) +#define EXYNOS_USB3_DEPEVT_EVENT_XferNotReady (3 << 6) +#define EXYNOS_USB3_DEPEVT_EVENT_XferInProgress (2 << 6) +#define EXYNOS_USB3_DEPEVT_EVENT_XferComplete (1 << 6) +#define EXYNOS_USB3_DEPEVT_EPNUM_MASK (0x1f << 1) +#define EXYNOS_USB3_DEPEVT_EPNUM_SHIFT 1 +#define EXYNOS_USB3_DEPEVT_EPNUM(_x) ((_x) << 1) + +/* Event Buffer Content for Device-Specific Events (DEVT) */ +#define EXYNOS_USB3_DEVT_EventParam_MASK (0xf << 16) +#define EXYNOS_USB3_DEVT_EventParam_SHIFT 16 +#define EXYNOS_USB3_DEVT_EventParam_SS (1 << 20) +#define EXYNOS_USB3_DEVT_EventParam(_x) ((_x) << 16) +#define EXYNOS_USB3_DEVT_EVENT_MASK (0xf << 8) +#define EXYNOS_USB3_DEVT_EVENT_SHIFT 8 +#define EXYNOS_USB3_DEVT_EVENT_VndrDevTstRcved (12 << 8) +#define EXYNOS_USB3_DEVT_EVENT_EvntOverflow (11 << 8) +#define EXYNOS_USB3_DEVT_EVENT_CmdCmplt (10 << 8) +#define EXYNOS_USB3_DEVT_EVENT_ErrticErr (9 << 8) +#define EXYNOS_USB3_DEVT_EVENT_Sof (7 << 8) +#define EXYNOS_USB3_DEVT_EVENT_EOPF (6 << 8) +#define EXYNOS_USB3_DEVT_EVENT_WkUpEvt (4 << 8) +#define EXYNOS_USB3_DEVT_EVENT_ULStChng (3 << 8) +#define EXYNOS_USB3_DEVT_EVENT_ConnectDone (2 << 8) +#define EXYNOS_USB3_DEVT_EVENT_USBRst (1 << 8) +#define EXYNOS_USB3_DEVT_EVENT_DisconnEvt (0 << 8) + +#define EXYNOS_USB3_GHWPARAMS8 0xC600 + +/* USB 2.0 OTG and Battery Charger registers */ +#define EXYNOS_USB3_OCFG 0xCC00 +#define EXYNOS_USB3_OCFG_OTG_Version (1 << 2) +#define EXYNOS_USB3_OCFG_HNPCap (1 << 1) +#define EXYNOS_USB3_OCFG_SRPCap (1 << 0) + +#define EXYNOS_USB3_OCTL 0xCC04 +#define EXYNOS_USB3_OCTL_PeriMode (1 << 6) +#define EXYNOS_USB3_OCTL_PrtPwrCtl (1 << 5) +#define EXYNOS_USB3_OCTL_HNPReq (1 << 4) +#define EXYNOS_USB3_OCTL_SesReq (1 << 3) +#define EXYNOS_USB3_OCTL_TermSelDLPulse (1 << 2) +#define EXYNOS_USB3_OCTL_DevSetHNPEn (1 << 1) +#define EXYNOS_USB3_OCTL_HstSetHNPEn (1 << 0) + +#define EXYNOS_USB3_OEVT 0xCC08 +#define EXYNOS_USB3_OEVT_DeviceMode (1 << 31) +#define EXYNOS_USB3_OEVT_OTGConIDStsChngEvnt (1 << 24) +#define EXYNOS_USB3_OEVT_OTGADevBHostEndEvnt (1 << 20) +#define EXYNOS_USB3_OEVT_OTGADevHostEvnt (1 << 19) +#define EXYNOS_USB3_OEVT_OTGADevHNPChngEvnt (1 << 18) +#define EXYNOS_USB3_OEVT_OTGADevSRPDetEvnt (1 << 17) +#define EXYNOS_USB3_OEVT_OTGADevSessEndDetEvnt (1 << 16) +#define EXYNOS_USB3_OEVT_OTGBDevBHostEndEvnt (1 << 11) +#define EXYNOS_USB3_OEVT_OTGBDevHNPChngEvnt (1 << 10) +#define EXYNOS_USB3_OEVT_OTGBDevSessVldDetEvnt (1 << 9) +#define EXYNOS_USB3_OEVT_OTGBDevVBUSChngEvnt (1 << 8) +#define EXYNOS_USB3_OEVT_BSesVld (1 << 3) +#define EXYNOS_USB3_OEVT_HstNegSts (1 << 2) +#define EXYNOS_USB3_OEVT_SesReqSts (1 << 1) +#define EXYNOS_USB3_OEVT_OEVTError (1 << 0) + +#define EXYNOS_USB3_OEVTEN 0xCC0C +#define EXYNOS_USB3_OEVTEN_OTGConIDStsChngEvntEn (1 << 24) +#define EXYNOS_USB3_OEVTEN_OTGADevBHostEndEvntEn (1 << 20) +#define EXYNOS_USB3_OEVTEN_OTGADevHostEvntEn (1 << 19) +#define EXYNOS_USB3_OEVTEN_OTGADevHNPChngEvntEn (1 << 18) +#define EXYNOS_USB3_OEVTEN_OTGADevSRPDetEvntEn (1 << 17) +#define EXYNOS_USB3_OEVTEN_OTGADevSessEndDetEvntEn (1 << 16) +#define EXYNOS_USB3_OEVTEN_OTGBDevBHostEndEvntEn (1 << 11) +#define EXYNOS_USB3_OEVTEN_OTGBDevHNPChngEvntEn (1 << 10) +#define EXYNOS_USB3_OEVTEN_OTGBDevSessVldDetEvntEn (1 << 9) +#define EXYNOS_USB3_OEVTEN_OTGBDevVBUSChngEvntEn (1 << 8) + +#define EXYNOS_USB3_OSTS 0xCC10 +#define EXYNOS_USB3_OSTS_OTG_state_MASK (0xf << 8) +#define EXYNOS_USB3_OSTS_OTG_state_SHIFT 8 +#define EXYNOS_USB3_OSTS_OTG_state(_x) ((_x) << 8) +#define EXYNOS_USB3_OSTS_PeripheralState (1 << 4) +#define EXYNOS_USB3_OSTS_xHCIPrtPower (1 << 3) +#define EXYNOS_USB3_OSTS_BSesVld (1 << 2) +#define EXYNOS_USB3_OSTS_VbusVld (1 << 1) +#define EXYNOS_USB3_OSTS_ConIDSts (1 << 0) + +#define EXYNOS_USB3_ADPCFG 0xCC20 +#define EXYNOS_USB3_ADPCFG_PrbPer_MASK (0x3 << 30) +#define EXYNOS_USB3_ADPCFG_PrbPer_SHIFT 30 +#define EXYNOS_USB3_ADPCFG_PrbPer(_x) ((_x) << 30) +#define EXYNOS_USB3_ADPCFG_PrbDelta_MASK (0x3 << 28) +#define EXYNOS_USB3_ADPCFG_PrbDelta_SHIFT 28 +#define EXYNOS_USB3_ADPCFG_PrbDelta(_x) ((_x) << 28) +#define EXYNOS_USB3_ADPCFG_PrbDschg_MASK (0x3 << 26) +#define EXYNOS_USB3_ADPCFG_PrbDschg_SHIFT 26 +#define EXYNOS_USB3_ADPCFG_PrbDschg(_x) ((_x) << 26) + +#define EXYNOS_USB3_ADPCTL 0xCC24 +#define EXYNOS_USB3_ADPCTL_EnaPrb (1 << 28) +#define EXYNOS_USB3_ADPCTL_EnaSns (1 << 27) +#define EXYNOS_USB3_ADPCTL_ADPEn (1 << 26) +#define EXYNOS_USB3_ADPCTL_ADPRes (1 << 25) +#define EXYNOS_USB3_ADPCTL_WB (1 << 24) + +#define EXYNOS_USB3_ADPEVT 0xCC28 +#define EXYNOS_USB3_ADPEVT_AdpPrbEvnt (1 << 28) +#define EXYNOS_USB3_ADPEVT_AdpSnsEvnt (1 << 27) +#define EXYNOS_USB3_ADPEVT_AdpTmoutEvnt (1 << 26) +#define EXYNOS_USB3_ADPEVT_ADPRstCmpltEvnt (1 << 25) +#define EXYNOS_USB3_ADPEVT_RTIM_MASK (0x7ff << 0) +#define EXYNOS_USB3_ADPEVT_RTIM_SHIFT 0 +#define EXYNOS_USB3_ADPEVT_RTIM(_x) ((_x) << 0) + +#define EXYNOS_USB3_ADPEVTEN 0xCC2C +#define EXYNOS_USB3_ADPEVTEN_AdpPrbEvntEn (1 << 28) +#define EXYNOS_USB3_ADPEVTEN_AdpSnsEvntEn (1 << 27) +#define EXYNOS_USB3_ADPEVTEN_AdpTmoutEvntEn (1 << 26) +#define EXYNOS_USB3_ADPEVTEN_ADPRstCmpltEvntEn (1 << 25) + +#define EXYNOS_USB3_BCFG 0xCC30 +#define EXYNOS_USB3_BCFG_IDDIG_SEL (1 << 1) +#define EXYNOS_USB3_BCFG_CHIRP_EN (1 << 0) + +#define EXYNOS_USB3_BCEVT 0xCC38 +#define EXYNOS_USB3_BCEVT_MV_ChngEvnt (1 << 24) +#define EXYNOS_USB3_BCEVT_MultValIdBc_MASK (0x1f << 0) +#define EXYNOS_USB3_BCEVT_MultValIdBc_SHIFT 0 +#define EXYNOS_USB3_BCEVT_MultValIdBc(_x) ((_x) << 0) + +#define EXYNOS_USB3_BCEVTEN 0xCC3C +#define EXYNOS_USB3_BCEVTEN_MV_ChngEvntEn (1 << 24) + +#endif /* __LINUX_USB_EXYNOS_USB3_DRD_H */ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB3Phy.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB3Phy.h new file mode 100644 index 000000000..f903e0cdc --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/Exynos5_USB3Phy.h @@ -0,0 +1,80 @@ +#ifndef _EFI_EXYNOS5_USB3_PHY_H_ +#define _EFI_EXYNOS5_USB3_PHY_H_ + +#define EXYNOS5_USB3_PHY_HOST_CTRL0 0x12100000 + +#define EXYNOS_USB3_LINKSYSTEM (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x04) +#define EXYNOS_USB3_PHYUTMI (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x08) +#define EXYNOS_USB3_PHYPIPE (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x0C) +#define EXYNOS_USB3_PHYCLKRST (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x10) +#define EXYNOS_USB3_PHYREG0 (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x14) +#define EXYNOS_USB3_PHYREG1 (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x18) +#define EXYNOS_USB3_PHYPARAM0 (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x1C) +#define EXYNOS_USB3_PHYPARAM1 (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x20) +#define EXYNOS_USB3_PHYTERM (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x24) +#define EXYNOS_USB3_PHYTEST (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x28) +#define EXYNOS_USB3_PHYADP (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x2C) +#define EXYNOS_USB3_PHYBATCHG (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x30) +#define EXYNOS_USB3_PHYRESUME (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x34) +#define EXYNOS_USB3_LINKPORT (EXYNOS5_USB3_PHY_HOST_CTRL0 + 0x44) + + +#define EXYNOS_USB3_PHYUTMI_OTGDISABLE (1 << 6) +#define EXYNOS_USB3_PHYUTMI_FORCESUSPEND (1 << 1) +#define EXYNOS_USB3_PHYUTMI_FORCESLEEP (1 << 0) + +#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_MASK (0xff << 23) +#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_SHIFT (23) +#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_LIMIT (0xff) +#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL(_x) ((_x) << 23) + +#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_MASK (0x03 << 21) +#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_SHIFT (21) +#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_LIMIT (0x03) +#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE(_x) ((_x) << 21) + +#define EXYNOS_USB3_PHYCLKRST_SSC_EN (1 << 20) +#define EXYNOS_USB3_PHYCLKRST_REF_SSP_EN (1 << 19) +#define EXYNOS_USB3_PHYCLKRST_REF_CLKDIV2 (1 << 18) + +#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11) +#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_SHIFT (11) +#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_LIMIT (0x7f) +#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER(_x) ((_x) << 11) + +#define EXYNOS_USB3_PHYCLKRST_SSC_EN (1 << 20) +#define EXYNOS_USB3_PHYCLKRST_REF_SSP_EN (1 << 19) +#define EXYNOS_USB3_PHYCLKRST_REF_CLKDIV2 (1 << 18) + +#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11) +#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_SHIFT (11) +#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_LIMIT (0x7f) +#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER(_x) ((_x) << 11) + +#define EXYNOS_USB3_PHYCLKRST_FSEL_MASK (0x3f << 5) +#define EXYNOS_USB3_PHYCLKRST_FSEL_SHIFT (5) +#define EXYNOS_USB3_PHYCLKRST_FSEL_LIMIT (0x3f) +#define EXYNOS_USB3_PHYCLKRST_FSEL(_x) ((_x) << 5) + +#define EXYNOS_USB3_PHYCLKRST_RETENABLEN (1 << 4) + +#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_MASK (0x03 << 2) +#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_SHIFT (2) +#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_LIMIT (0x03) +#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL(_x) ((_x) << 2) + +#define EXYNOS_USB3_PHYCLKRST_PORTRESET (1 << 1) +#define EXYNOS_USB3_PHYCLKRST_COMMONONN (1 << 0) + + +//------------------------------------------------------- +// Functions +//------------------------------------------------------- + +void exynos5_usb_phy30_init(void); +void exynos_xhci_phy_set(void); +UINT32 exynos_xhci_change_mode(void); + +#endif + + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.c new file mode 100644 index 000000000..a4295cc85 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.c @@ -0,0 +1,684 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PciEmulation.h" +#include "Exynos5_USB2Phy.h" +#include "Exynos5_USB3Phy.h" +#include "Exynos5_USB3Drd.h" + +#define HOST_CONTROLLER_OPERATION_REG_SIZE 0x44 +#define USBDRD_CONTROLLER_OPERATION_REG_SIZE 0x400 + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + PCI_DEVICE_PATH PciDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_IO_DEVICE_PATH; + +typedef struct { + UINT32 Signature; + EFI_PCI_IO_DEVICE_PATH DevicePath; + EFI_PCI_IO_PROTOCOL PciIoProtocol; + PCI_TYPE00 *ConfigSpace; + PCI_ROOT_BRIDGE RootBridge; + UINTN Segment; +} EFI_PCI_IO_PRIVATE_DATA; + +#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o') +#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE) + +EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplateUSB2 = +{ + { + { ACPI_DEVICE_PATH, ACPI_DP, sizeof (ACPI_HID_DEVICE_PATH), 0}, + EISA_PNP_ID(0x0A03), // HID + 0 // UID + }, + { + { HARDWARE_DEVICE_PATH, HW_PCI_DP, sizeof (PCI_DEVICE_PATH), 0}, + 0, + 0 + }, + { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} +}; + +EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplateUSB3 = +{ + { + { ACPI_DEVICE_PATH, ACPI_DP, sizeof (ACPI_HID_DEVICE_PATH), 0}, + EISA_PNP_ID(0x0A03), // HID + 1 // UID + }, + { + { HARDWARE_DEVICE_PATH, HW_PCI_DP, sizeof (PCI_DEVICE_PATH), 0}, + 0, + 1 + }, + { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} +}; + +EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplateUSB1 = +{ + { + { ACPI_DEVICE_PATH, ACPI_DP, sizeof (ACPI_HID_DEVICE_PATH), 0}, + EISA_PNP_ID(0x0A03), // HID + 2 // UID + }, + { + { HARDWARE_DEVICE_PATH, HW_PCI_DP, sizeof (PCI_DEVICE_PATH), 0}, + 0, + 2 + }, + { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} +}; + + +STATIC +VOID +ConfigureUSBHost ( + VOID + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __func__, __LINE__)); + + exynos5_usb_phy20_init(); +#if defined(XHCI_SUPPORT) + exynos5_usb_phy30_init(); + exynos_xhci_change_mode(); + exynos_xhci_phy_set(); +#endif + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); +} + + +EFI_STATUS +PciIoPollMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoPollIo ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoMemRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return PciRootBridgeIoMemRead (&Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, + Count, + Buffer + ); +} + +EFI_STATUS +PciIoMemWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return PciRootBridgeIoMemWrite (&Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, + Count, + Buffer + ); +} + +EFI_STATUS +PciIoIoRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoIoWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoPciRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Count, + TRUE, + (PTR)(UINTN)Buffer, + TRUE, + (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset) + ); +} + +EFI_STATUS +PciIoPciWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Count, + TRUE, + (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset), + TRUE, + (PTR)(UINTN)Buffer + ); +} + +EFI_STATUS +PciIoCopyMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoMap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + DMA_MAP_OPERATION DmaOperation; + + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + if (Operation == EfiPciIoOperationBusMasterRead) { + DmaOperation = MapOperationBusMasterRead; + } else if (Operation == EfiPciIoOperationBusMasterWrite) { + DmaOperation = MapOperationBusMasterWrite; + } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) { + DmaOperation = MapOperationBusMasterCommonBuffer; + } else { + return EFI_INVALID_PARAMETER; + } + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping); +} + +EFI_STATUS +PciIoUnmap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return DmaUnmap (Mapping); +} + +EFI_STATUS +PciIoAllocateBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) { + // Check this + return EFI_UNSUPPORTED; + } + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return DmaAllocateBuffer (MemoryType, Pages, HostAddress); +} + + +EFI_STATUS +PciIoFreeBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return DmaFreeBuffer (Pages, HostAddress); +} + + +EFI_STATUS +PciIoFlush ( + IN EFI_PCI_IO_PROTOCOL *This + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoGetLocation ( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + if (SegmentNumber != NULL) { + *SegmentNumber = Private->Segment; + } + + if (BusNumber != NULL) { + *BusNumber = 0xff; + } + + if (DeviceNumber != NULL) { + *DeviceNumber = 0; + } + + if (FunctionNumber != NULL) { + *FunctionNumber = 0; + } + + DEBUG((EFI_D_INFO, "--%a:%d\n", __FUNCTION__, __LINE__)); + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ) +{ + DEBUG((EFI_D_INFO, "++%a:%d\n", __FUNCTION__, __LINE__)); + switch (Operation) { + case EfiPciIoAttributeOperationGet: + case EfiPciIoAttributeOperationSupported: + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + // We are not a real PCI device so just say things we kind of do + *Result = EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_DEVICE_ENABLE; + break; + + case EfiPciIoAttributeOperationSet: + case EfiPciIoAttributeOperationEnable: + case EfiPciIoAttributeOperationDisable: + // Since we are not a real PCI device no enable/set or disable operations exist. + DEBUG((EFI_D_INFO, "--%a(Set:1, Enable:2, Disable:3)(%d):%d\n", __FUNCTION__, Operation,__LINE__)); + return EFI_SUCCESS; + + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + }; + DEBUG((EFI_D_INFO, "--%a(Get:0, Supported:4)(%d):%d\n", __FUNCTION__, Operation,__LINE__)); + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoGetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoSetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_PCI_IO_PROTOCOL PciIoTemplate = +{ + PciIoPollMem, + PciIoPollIo, + PciIoMemRead, + PciIoMemWrite, + PciIoIoRead, + PciIoIoWrite, + PciIoPciRead, + PciIoPciWrite, + PciIoCopyMem, + PciIoMap, + PciIoUnmap, + PciIoAllocateBuffer, + PciIoFreeBuffer, + PciIoFlush, + PciIoGetLocation, + PciIoAttributes, + PciIoGetBarAttributes, + PciIoSetBarAttributes, + 0, + 0 +}; + +EFI_STATUS +EFIAPI +PciEmulationEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE HandleUSB2; + EFI_PCI_IO_PRIVATE_DATA *PrivateUSB2; +#if defined(OHCI_SUPPORT) + EFI_HANDLE HandleUSB1; + EFI_PCI_IO_PRIVATE_DATA *PrivateUSB1; +#endif +#if defined(XHCI_SUPPORT) + EFI_HANDLE HandleUSB3; + EFI_PCI_IO_PRIVATE_DATA *PrivateUSB3; +#endif + UINT8 CapabilityLength; + UINT8 PhysicalPorts; +#if defined(OHCI_SUPPORT) +#else + UINTN Count; +#endif + + //Configure USB host for Exynos. + ConfigureUSBHost(); + + // Create a private structure for USB 2.0 + PrivateUSB2 = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA)); + if (PrivateUSB2 == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + PrivateUSB2->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature + PrivateUSB2->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too + PrivateUSB2->RootBridge.MemoryStart = USB_EHCI_HCCAPBASE; // Get the USB capability register base + PrivateUSB2->Segment = 0; // Default to segment zero + + +#if defined(XHCI_SUPPORT) + // Create a private structure for USB 3.0 + PrivateUSB3 = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA)); + if (PrivateUSB3 == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + PrivateUSB3->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature + PrivateUSB3->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too + PrivateUSB3->RootBridge.MemoryStart = USB_XHCI_HCCAPBASE; // Get the USB capability register base + PrivateUSB3->Segment = 0; // Default to segment zero +#endif + +#if defined(OHCI_SUPPORT) + // Create a private structure for USB 1.0 + PrivateUSB1 = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA)); + if (PrivateUSB1 == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + PrivateUSB1->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature + PrivateUSB1->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too + PrivateUSB1->RootBridge.MemoryStart = USB_OHCI_HCCAPBASE; // Get the USB capability register base + PrivateUSB1->Segment = 0; // Default to segment zero +#endif + + // USB 2.0 + // Find out the capability register length and number of physical ports. + CapabilityLength = MmioRead8(PrivateUSB2->RootBridge.MemoryStart); + PhysicalPorts = (MmioRead32 (PrivateUSB2->RootBridge.MemoryStart + 0x4)) & 0x0000000F; + + // Calculate the total size of the USB registers. + PrivateUSB2->RootBridge.MemorySize = CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1)); + + // Enable Port Power bit in Port status and control registers in EHCI register space. + // Port Power Control (PPC) bit in the HCSPARAMS register is already set which indicates + // host controller implementation includes port power control. + for (Count = 0; Count < PhysicalPorts; Count++) { + MmioOr32 ((PrivateUSB2->RootBridge.MemoryStart + CapabilityLength + HOST_CONTROLLER_OPERATION_REG_SIZE + 4*Count), 0x00001000); + } + +#if defined(XHCI_SUPPORT) + // USB 3.0 + // Find out the capability register length and number of physical ports. + CapabilityLength = MmioRead8(PrivateUSB3->RootBridge.MemoryStart); + PhysicalPorts = ((MmioRead32 (PrivateUSB3->RootBridge.MemoryStart + 0x4)) & 0xFF000000) >> 24; + + // Calculate the total size of the USB registers. + // 0x20 0x400 0x10 + //Private->RootBridge.MemorySize = CapabilityLength + (USBDRD_CONTROLLER_OPERATION_REG_SIZE + (0x10 * (PhysicalPorts - 1))); + PrivateUSB3->RootBridge.MemorySize = 0x100000; + + for (Count = 0; Count < PhysicalPorts; Count++) { + MmioOr32 (PrivateUSB3->RootBridge.MemoryStart + CapabilityLength + USBDRD_CONTROLLER_OPERATION_REG_SIZE + (0x10 * Count), 0x00000200); + } +#endif + +#if defined(OHCI_SUPPORT) + CapabilityLength = 0; + PhysicalPorts = 3; + PrivateUSB1->RootBridge.MemorySize = 0x60; +#endif + + + // USB 2.0 + // Create fake PCI config space. + PrivateUSB2->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00)); + if (PrivateUSB2->ConfigSpace == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePool(PrivateUSB2); + return Status; + } + + // Configure PCI config space + PrivateUSB2->ConfigSpace->Hdr.VendorId = 0x3530; + PrivateUSB2->ConfigSpace->Hdr.DeviceId = 0x3530; + PrivateUSB2->ConfigSpace->Hdr.ClassCode[0] = 0x20; + PrivateUSB2->ConfigSpace->Hdr.ClassCode[1] = 0x03; + PrivateUSB2->ConfigSpace->Hdr.ClassCode[2] = 0x0C; + PrivateUSB2->ConfigSpace->Device.Bar[0] = PrivateUSB2->RootBridge.MemoryStart; + +#if defined(XHCI_SUPPORT) + // USB 3.0 + // Create fake PCI config space. + PrivateUSB3->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00)); + if (PrivateUSB3->ConfigSpace == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePool(PrivateUSB3); + return Status; + } + + // Configure PCI config space + PrivateUSB3->ConfigSpace->Hdr.VendorId = 0x3530; + PrivateUSB3->ConfigSpace->Hdr.DeviceId = 0x3530; + PrivateUSB3->ConfigSpace->Hdr.ClassCode[0] = 0x30; /* 0x20 : EHIC, 0x30 : XHCI */ + PrivateUSB3->ConfigSpace->Hdr.ClassCode[1] = 0x03; + PrivateUSB3->ConfigSpace->Hdr.ClassCode[2] = 0x0C; + PrivateUSB3->ConfigSpace->Device.Bar[0] = PrivateUSB3->RootBridge.MemoryStart; +#endif + +#if defined(OHCI_SUPPORT) + // USB 1.0 + // Create fake PCI config space. + PrivateUSB1->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00)); + if (PrivateUSB1->ConfigSpace == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePool(PrivateUSB1); + return Status; + } + + // Configure PCI config space + PrivateUSB1->ConfigSpace->Hdr.VendorId = 0x3530; + PrivateUSB1->ConfigSpace->Hdr.DeviceId = 0x3530; + PrivateUSB1->ConfigSpace->Hdr.ClassCode[0] = 0x10; + PrivateUSB1->ConfigSpace->Hdr.ClassCode[1] = 0x03; + PrivateUSB1->ConfigSpace->Hdr.ClassCode[2] = 0x0C; + PrivateUSB1->ConfigSpace->Device.Bar[0] = PrivateUSB2->RootBridge.MemoryStart; +#endif + + + HandleUSB2 = NULL; + + // USB 2.0 + // Unique device path. + CopyMem(&PrivateUSB2->DevicePath, &PciIoDevicePathTemplateUSB2, sizeof(PciIoDevicePathTemplateUSB2)); + PrivateUSB2->DevicePath.AcpiDevicePath.UID = 0; + // Copy protocol structure + CopyMem(&PrivateUSB2->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate)); + + Status = gBS->InstallMultipleProtocolInterfaces(&HandleUSB2, + &gEfiPciIoProtocolGuid, &PrivateUSB2->PciIoProtocol, + &gEfiDevicePathProtocolGuid, &PrivateUSB2->DevicePath, + NULL); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n")); + } + +#if defined(XHCI_SUPPORT) + HandleUSB3 = NULL; + + // USB 3.0 + // Unique device path. + CopyMem(&PrivateUSB3->DevicePath, &PciIoDevicePathTemplateUSB3, sizeof(PciIoDevicePathTemplateUSB3)); + PrivateUSB3->DevicePath.AcpiDevicePath.UID = 1; + // Copy protocol structure + CopyMem(&PrivateUSB3->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate)); + + + Status = gBS->InstallMultipleProtocolInterfaces(&HandleUSB3, + &gEfiPciIoProtocolGuid, &PrivateUSB3->PciIoProtocol, + &gEfiDevicePathProtocolGuid, &PrivateUSB3->DevicePath, + NULL); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n")); + } +#endif + +#if defined(OHCI_SUPPORT) + HandleUSB1 = NULL; + + // USB 1.0 + // Unique device path. + CopyMem(&PrivateUSB1->DevicePath, &PciIoDevicePathTemplateUSB1, sizeof(PciIoDevicePathTemplateUSB1)); + PrivateUSB1->DevicePath.AcpiDevicePath.UID = 2; + // Copy protocol structure + CopyMem(&PrivateUSB1->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate)); + + Status = gBS->InstallMultipleProtocolInterfaces(&HandleUSB1, + &gEfiPciIoProtocolGuid, &PrivateUSB1->PciIoProtocol, + &gEfiDevicePathProtocolGuid, &PrivateUSB1->DevicePath, + NULL); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n")); + } +#endif + + + return Status; +} + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.h new file mode 100644 index 000000000..7f0e3106e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.h @@ -0,0 +1,290 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_ + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PciLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DmaLib.h> + +#include <Protocol/EmbeddedExternalDevice.h> +#include <Protocol/DevicePath.h> +#include <Protocol/PciIo.h> +#include <Protocol/PciRootBridgeIo.h> +#include <Protocol/PciHostBridgeResourceAllocation.h> + +#include <IndustryStandard/Pci22.h> +#include <IndustryStandard/Acpi.h> + + +//#define OHCI_SUPPORT +#define XHCI_SUPPORT + + +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFFULL +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL +#define EFI_RESOURCE_SATISFIED 0x0000000000000000ULL + + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + + +#define ACPI_CONFIG_IO 0 +#define ACPI_CONFIG_MMIO 1 +#define ACPI_CONFIG_BUS 2 + +typedef struct { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Desc[3]; + EFI_ACPI_END_TAG_DESCRIPTOR EndDesc; +} ACPI_CONFIG_INFO; + + +#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F') + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io; + EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath; + + UINT8 StartBus; + UINT8 EndBus; + UINT16 Type; + UINT32 MemoryStart; + UINT32 MemorySize; + UINTN IoOffset; + UINT32 IoStart; + UINT32 IoSize; + UINT64 PciAttributes; + + ACPI_CONFIG_INFO *Config; + +} PCI_ROOT_BRIDGE; + + +#define INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE, Io, PCI_ROOT_BRIDGE_SIGNATURE) + + +typedef union { + UINT8 volatile *buf; + UINT8 volatile *ui8; + UINT16 volatile *ui16; + UINT32 volatile *ui32; + UINT64 volatile *ui64; + UINTN volatile ui; +} PTR; + + + +EFI_STATUS +EFIAPI +PciRootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ); + +BOOLEAN +PciIoMemAddressValid ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Address + ); + +EFI_STATUS +EmulatePciIoForEhci ( + INTN MvPciIfMaxIf + ); + +#endif + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.inf new file mode 100644 index 000000000..f56fe6c04 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciEmulation.inf @@ -0,0 +1,64 @@ +/** @file + + Copyright (c) 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ExynosPciEmulation + FILE_GUID = feaa2e2b-53ac-4d5e-ae10-1efd5da4a2ba + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = PciEmulationEntryPoint + +[Sources.common] + Exynos5_USB2Phy.h + Exynos5_USB3Phy.h + Exynos5_USB.c + PciRootBridgeIo.c + PciEmulation.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + SamsungPlatformPkg/SamsungPlatformPkg.dec + +[LibraryClasses] + BaseLib + DxeServicesTableLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + IoLib + DmaLib + TimerLib + +[Pcd] + gExynosPkgTokenSpaceGuid.PcdExynos5250Evt1 + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiPciHostBridgeResourceAllocationProtocolGuid + gEfiPciIoProtocolGuid + gSamsungPlatformGpioProtocolGuid ## GPIO Protocol + +[Depex] + gEfiMetronomeArchProtocolGuid + + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciRootBridgeIo.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciRootBridgeIo.c new file mode 100644 index 000000000..2f5b1aa1d --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/PciEmulation/PciRootBridgeIo.c @@ -0,0 +1,306 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PciEmulation.h" + +BOOLEAN +PciRootBridgeMemAddressValid ( + IN PCI_ROOT_BRIDGE *Private, + IN UINT64 Address + ) +{ + if ((Address >= Private->MemoryStart) && (Address < (Private->MemoryStart + Private->MemorySize))) { + return TRUE; + } + + return FALSE; +} + + +EFI_STATUS +PciRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ) +{ + UINTN Stride; + UINTN InStride; + UINTN OutStride; + + + Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); + Stride = (UINTN)1 << Width; + InStride = InStrideFlag ? Stride : 0; + OutStride = OutStrideFlag ? Stride : 0; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiPciWidthUint8: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui8 = *Out.ui8; + } + break; + case EfiPciWidthUint16: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui16 = *Out.ui16; + } + break; + case EfiPciWidthUint32: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui32 = *Out.ui32; + } + break; + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return EFI_SUCCESS; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE *Private; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (!PciRootBridgeMemAddressValid (Private, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + In.buf = Buffer; + Out.buf = (VOID *)(UINTN) Address; + + switch (Width) { + case EfiPciWidthUint8: + case EfiPciWidthUint16: + case EfiPciWidthUint32: + case EfiPciWidthUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + + case EfiPciWidthFifoUint8: + case EfiPciWidthFifoUint16: + case EfiPciWidthFifoUint32: + case EfiPciWidthFifoUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + + case EfiPciWidthFillUint8: + case EfiPciWidthFillUint16: + case EfiPciWidthFillUint32: + case EfiPciWidthFillUint64: + return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + + default: + break; + } + + return EFI_INVALID_PARAMETER; +} + + + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE *Private; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (!PciRootBridgeMemAddressValid (Private, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + In.buf = (VOID *)(UINTN) Address; + Out.buf = Buffer; + + switch (Width) { + case EfiPciWidthUint8: + case EfiPciWidthUint16: + case EfiPciWidthUint32: + case EfiPciWidthUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + + case EfiPciWidthFifoUint8: + case EfiPciWidthFifoUint16: + case EfiPciWidthFifoUint32: + case EfiPciWidthFifoUint64: + return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + + case EfiPciWidthFillUint8: + case EfiPciWidthFillUint16: + case EfiPciWidthFillUint32: + case EfiPciWidthFillUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + + default: + break; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + + + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +} + + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.c new file mode 100644 index 000000000..7254bd1fa --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.c @@ -0,0 +1,120 @@ +/** @file + Implement EFI Random Number Generator runtime services via Rng Lib. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Uefi.h> + +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/DebugLib.h> +#include <Library/ArmGicLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include <Protocol/ExynosRng.h> + +#include "RngDxe.h" + +#define CLKDIV 512 +#define RNGSEL 5 + +/** + * Generates a pseudorandom byte stream of the specified size. + * + * If Output is NULL, then return FALSE. + * + * @param[out] Output Pointer to buffer to receive random value + * @param[in] Size Size of random bytes to generate + * + * @retval TRUE Pseudorandom byte stream generated successfully. + * @retval FALSE Pseudorandom number generator fails to generate due to lack of entropy. + * + **/ +EFI_STATUS +EFIAPI +RngDxeRandomBytes ( + IN CONST EFI_RNG_PROTOCOL *This, + OUT UINT8 *Output, + IN UINTN Size + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 TRNGBase; + UINT32 value, count, fifo_addr; + + TRNGBase = PcdGet32(PcdCryptoBase); + + /* Set Clock Divider */ + MmioWrite32(TRNGBase + TRNG_CLKDIV, CLKDIV); + + /* Select RNG Engine */ + value = TRNG_ENABLE | TRNG_MANUAL_ENABLE | RNGSEL; + MmioWrite32(TRNGBase + TRNG_CTRL, value); + + /* Select and Enable Post Processor */ + value = TRNG_POST_ENABLE | TRNG_POST_SEL_LFSR; + MmioWrite32(TRNGBase + TRNG_POST_CTRL, value); + + /* Disable Online Tester */ + MmioWrite32(TRNGBase + TRNG_ONLINE_CTRL, 0); + + /* Set FIFO pointer as number of random bits */ + MmioWrite32(TRNGBase + TRNG_FIFO_CTRL, Size << 3); + + /* Poll FIFO pointer until TRNG_FIFO_CTRL.FIFOPTR == 0 */ + while (MmioRead32(TRNGBase + TRNG_FIFO_CTRL)); + + /* Read TRNG FIFO */ + for (count = 0; count < (Size >> 2); count++) { + fifo_addr = TRNG_FIFO_0 + (count << 2); + value = MmioRead32(TRNGBase + fifo_addr); + CopyMem((UINT8 *)((UINT32)Output + (count << 2)), &value, sizeof(value)); + } + + return Status; +} + +EFI_RNG_PROTOCOL gRng = { + RngDxeRandomBytes +}; + +/** + Initialize the state information for the RngDxe + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +RngDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + Status = gBS->InstallMultipleProtocolInterfaces( + &ImageHandle, + &gSamsungPlatformRngProtocolGuid, + &gRng, + NULL + ); + + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.h new file mode 100644 index 000000000..6a1ab107e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.h @@ -0,0 +1,40 @@ +#ifndef __CRYPTRAND_H__ +#define __CRYPTRAND_H__ + +/* + * TRNG SFR Address + */ +#define SSS_TRNG_OFFSET (0x600) + +#define TRNG_CLKDIV (SSS_TRNG_OFFSET + 0x00) +#define TRNG_CTRL (SSS_TRNG_OFFSET + 0x20) +#define TRNG_POST_CTRL (SSS_TRNG_OFFSET + 0x30) +#define TRNG_ONLINE_CTRL (SSS_TRNG_OFFSET + 0x40) +#define TRNG_ONLINE_STAT (SSS_TRNG_OFFSET + 0x44) +#define TRNG_ONLINE_MAXCHI2 (SSS_TRNG_OFFSET + 0x48) + +#define TRNG_FIFO_CTRL (SSS_TRNG_OFFSET + 0x50) +#define TRNG_FIFO_0 (SSS_TRNG_OFFSET + 0x80) +#define TRNG_FIFO_1 (SSS_TRNG_OFFSET + 0x84) +#define TRNG_FIFO_2 (SSS_TRNG_OFFSET + 0x88) +#define TRNG_FIFO_3 (SSS_TRNG_OFFSET + 0x8C) +#define TRNG_FIFO_4 (SSS_TRNG_OFFSET + 0x90) +#define TRNG_FIFO_5 (SSS_TRNG_OFFSET + 0x94) +#define TRNG_FIFO_6 (SSS_TRNG_OFFSET + 0x98) +#define TRNG_FIFO_7 (SSS_TRNG_OFFSET + 0x9C) + +/* TRNG CTRL */ +#define TRNG_ENABLE (0x1 << 31) +#define TRNG_MANUAL_ENABLE (0x1 << 30) + +/* TRNG POST CTRL */ +#define TRNG_POST_ENABLE (0x1 << 31) +#define TRNG_POST_SEL_BYPASS (0x0 << 0) +#define TRNG_POST_SEL_LFSR (0x1 << 0) +#define TRNG_POST_SEL_VON (0x2 << 0) +#define TRNG_POST_SEL_XOR (0x3 << 0) + +/* TRNG ONLINE CTRL */ +#define TRNG_ONLINE_TESTER_ENABLE (0x1 << 31) +#endif + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.inf new file mode 100644 index 000000000..87c0e3490 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/RngDxe/RngDxe.inf @@ -0,0 +1,49 @@ +#/** @file +# CryptRand library implementation +# +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RngDxe + FILE_GUID = cc605e80-ef94-4d5c-9153-364c92b0adc1 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = RngDxeInitialize + +[Sources] + RngDxe.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + SamsungPlatformPkg/SamsungPlatformPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UncachedMemoryAllocationLib + DebugLib + IoLib + +[Guids] + +[Protocols] + gSamsungPlatformRngProtocolGuid + +[Pcd] + gExynosPkgTokenSpaceGuid.PcdCryptoBase + +[Depex] + TRUE diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.c new file mode 100755 index 000000000..0c3a219a4 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.c @@ -0,0 +1,1348 @@ +/** @file + MMC/SD Card driver for Secure Digital Host Controller + + This driver always produces a BlockIo protocol but it starts off with no Media + present. A TimerCallBack detects when media is inserted or removed and after + a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the + media to be detected (or removed) and the BlockIo Media structure will get + updated. No MMC/SD Card harward registers are updated until the first BlockIo + ReadBlocks/WriteBlocks after media has been insterted (booting with a card + plugged in counts as an insertion event). + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include <Library/TimerLib.h> +#include <Library/PcdLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Protocol/ExynosGpio.h> +#include <Platform/ArmPlatform.h> +#include <Platform/Exynos5250.h> +#include <Platform/Arndale5250.h> + +#include "SDHCDxe.h" + + +#define DateInformation "20120810_001" + + +MSHC_OPERATION_MODE MSHC_operation_mode=MSHC_FIFO; +//MSHC_OPERATION_MODE MSHC_operation_mode=MSHC_IDMA; + + +//#undef EFI_D_INFO +//#define EFI_D_INFO 1 + + +CARD_INFO gCardInfo; +EFI_EVENT gTimerEvent; +BOOLEAN gMediaChange = FALSE; + + +EFI_BLOCK_IO_MEDIA gSDMMCMedia = { + SIGNATURE_32('s','d','h','c'), // MediaId + TRUE, // RemovableMedia + FALSE, // MediaPresent + FALSE, // LogicalPartition + FALSE, // ReadOnly + FALSE, // WriteCaching + 512, // BlockSize + 4, // IoAlign + 0, // Pad + 0 // LastBlock +}; + +typedef struct { + VENDOR_DEVICE_PATH Mmc; + EFI_DEVICE_PATH End; +} MSHC_DEVICE_PATH; + +MSHC_DEVICE_PATH gMSHCDevicePath = { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8)(sizeof(VENDOR_DEVICE_PATH)), + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8), + 0x3a02e7fe, 0x649, 0x4fb4, 0xbe, 0x4f, 0xa8, 0x62, 0xca, 0x18, 0x72, 0xa9 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } +}; + + +// +// Internal Functions +// + + +VOID +ParseCardCIDData ( + UINT32 Response0, + UINT32 Response1, + UINT32 Response2, + UINT32 Response3 + ) +{ + gCardInfo.CIDData.MDT = ((Response0 >> 8) & 0xFFF); + gCardInfo.CIDData.PSN = (((Response0 >> 24) & 0xFF) | ((Response1 & 0xFFFFFF) << 8)); + gCardInfo.CIDData.PRV = ((Response1 >> 24) & 0xFF); + gCardInfo.CIDData.PNM[4] = ((Response2) & 0xFF); + gCardInfo.CIDData.PNM[3] = ((Response2 >> 8) & 0xFF); + gCardInfo.CIDData.PNM[2] = ((Response2 >> 16) & 0xFF); + gCardInfo.CIDData.PNM[1] = ((Response2 >> 24) & 0xFF); + gCardInfo.CIDData.PNM[0] = ((Response3) & 0xFF); + gCardInfo.CIDData.OID = ((Response3 >> 8) & 0xFFFF); + gCardInfo.CIDData.MID = ((Response3 >> 24) & 0xFF); +} + + +EFI_STATUS +MSHC_SendCmd ( + UINTN Cmd, + UINTN CmdInterruptEnableVal, + UINTN CmdArgument + ) +{ + UINTN MmcStatus = 0; + volatile UINTN RetryCount = 0; + int cmd_flags = 0; + int timeout=0; + UINT32 SdMmcBaseAddr; + //UINT32 MSHCRintStatus=0; + + DEBUG ((EFI_D_INFO, "CMD = %d Argument=0x%x\n", (Cmd&0x3F), CmdArgument)); + + timeout = MAX_RETRY_COUNT; + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + //1. Check if Data busy or not + while(MmioRead32(SdMmcBaseAddr + MSHCI_STATUS) & (DATA_BUSY)) + { + if (timeout == 0) + { + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd timeout : CMD = %d\n", Cmd)); + return EFI_DEVICE_ERROR; + } + timeout--; + MicroSecondDelay(1); + } + + // 2. Check if Raw interrupt is command done + /*MSHCRintStatus = MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS); + if ((MSHCRintStatus & (INTMSK_CDONE|INTMSK_ACD)) == 0) + { + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd interrupt error : INT = %x\n", MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS))); + } */ + + // 3. Clear Raw interrupt + MmioWrite32 ((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_ALL); + + // 4. prepare data + //mshci_reset_fifo(); + + //5. Set command argument register + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMDARG), CmdArgument); + + // 6. transfer data + + //Enable interrupt enable events to occur + // EVT1 do not need interrupt mask, use Raw interrupt + //MmioWrite32 ((SdMmcBaseAddr + MSHCI_INTMSK), CmdInterruptEnableVal); + + // 7. trasfer data + + //8. Send a command + cmd_flags = (Cmd & 0x3F); + if(Cmd & (RSPTYP48 | RSPTYP48B | RSPTYP136)) + { + cmd_flags |= CMD_RESP_EXP_BIT; + if(Cmd & RSPTYP136) + cmd_flags |= CMD_RESP_LENGTH_BIT; + } + + //if((Cmd==CMD17)|(Cmd==CMD18)|(Cmd==CMD8)) + if((Cmd==CMD17)|(Cmd==CMD18)) + { + cmd_flags |= CMD_DATA_EXP_BIT; + //DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Read\n")); + } + + if((Cmd==CMD24)|(Cmd==CMD25)) + { + cmd_flags |= CMD_DATA_EXP_BIT | CMD_RW_BIT; + //DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Write\n")); + + } + + if (Cmd & ENCMDCRC) + { + cmd_flags |= CMD_CHECK_CRC_BIT; + } + //cmd_flags |= (CMD_STRT_BIT | CMD_USE_HOLD_REG | CMD_WAIT_PRV_DAT_BIT|CMD_SENT_AUTO_STOP_BIT); + cmd_flags |= (CMD_STRT_BIT | CMD_USE_HOLD_REG | CMD_WAIT_PRV_DAT_BIT); + DEBUG ((EFI_D_INFO, "CMD flag = 0x%x\n", cmd_flags)); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), cmd_flags); + MicroSecondDelay(1); + + //9. Check for the Raw interrupt + //wait for command complete by busy waiting. + for (RetryCount; RetryCount<MAX_RETRY_COUNT; RetryCount++) + { + MmcStatus = MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS); + if (MmcStatus & INTMSK_CDONE) + { + break; + } + } + + if (RetryCount == MAX_RETRY_COUNT) + { + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd timeout CMD:%d RINT:0x%x\n",(Cmd&0x3F) ,MmcStatus)); + return EFI_TIMEOUT; + } + + if(MmcStatus & INTMSK_RTO) + { + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd Response timeout CMD:%d RINT:0x%x\n", (Cmd & 0x3F),MmcStatus)); + return EFI_TIMEOUT; + + } + else if (MmcStatus & INTMSK_RE) + { + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd Response Error RINT:0x%x\n", MmcStatus)); + return EFI_TIMEOUT; + } + else if(MmcStatus & INTMSK_RCRC) + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd Response CRC Err RINT:0x%x\n", MmcStatus)); + else if(MmcStatus & INTMSK_DCRC) + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd Data CRC Err RINT:0x%x\n", MmcStatus)); + else if(MmcStatus & INTMSK_HLE) + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd HLE Err RINT:0x%x\n", MmcStatus)); + else if(MmcStatus & INTMSK_SBE) + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd SBE Err RINT:0x%x\n", MmcStatus)); + else if(MmcStatus & INTMSK_EBE) + DEBUG ((EFI_D_ERROR, "SDHC::MSHC_SendCmd EBE Err RINT:0x%x\n", MmcStatus)); + + return EFI_SUCCESS; +} + +static const UINT32 FreqUnit[4]={10, 100, 1000, 10000}; +static const UINT8 MultiFactor[16]={0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80}; + +void PrintCardInfo() +{ +#if !defined(MDEPKG_NDEBUG) + UINT8 TransSpeed = gCardInfo.CSDData.TRAN_SPEED; + + DEBUG ((EFI_D_INFO, "SDHC::READ_BL_LEN %d\n", gCardInfo.CSDData.READ_BL_LEN)); + DEBUG ((EFI_D_INFO, "SDHC::CSize %d\n", gCardInfo.CSDData.C_SIZELow2 | (gCardInfo.CSDData.C_SIZEHigh10 << 2))); + DEBUG ((EFI_D_INFO, "SDHC::MULTI %d\n", gCardInfo.CSDData.C_SIZE_MULT)); + DEBUG ((EFI_D_INFO, "SDHC::Speed %d\n", (FreqUnit[TransSpeed&0x7]*MultiFactor[TransSpeed>>3]))); +#endif +} + + +#define EXT_CSD_SIZE 128 +UINT32 Ext_csd[EXT_CSD_SIZE]; +VOID GetEXTCSD() +{ + gCardInfo.NumBlocks = 0x1D4C000; + DEBUG ((EFI_D_INFO, "SDHC:: default block number : 0x1D4C000")); + + UINTN cmdarg = 0; + EFI_STATUS Status = EFI_SUCCESS; + + cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_HS_TIMING << 16) | + (0 << 8); + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, cmdarg); + + cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH << 16) | + (EXT_CSD_BUS_WIDTH_1 << 8); + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, cmdarg); + + cmdarg = 0; + Status = MSHC_SendCmd (CMD8, CMD8_INT_EN, cmdarg); + + gCardInfo.BlockSize = BLEN_512BYTES; + + if (!EFI_ERROR(Status)) + { + DEBUG ((EFI_D_INFO, "SDHC::EXT CSD \n")); + PrepareTransfer(&Ext_csd[0], 1, READ); + //MSHC_ReadDMA(&Ext_csd[0], 1); + MSHC_ReadFIFO(EXT_CSD_SIZE, &Ext_csd[0]); + gCardInfo.NumBlocks = Ext_csd[EXT_CSD_SEC_CNT/4]; + MicroSecondDelay(1000); + DEBUG ((1, "SDHC::Size:%dMB\n", (gCardInfo.NumBlocks/2048))); + } + +} + +VOID +GetBlockInformation ( + UINTN *BlockSize, + UINTN *NumBlocks + ) +{ + CSD_SDV2 *CsdSDV2Data; + UINTN CardSize; + + + if (gCardInfo.CardType == SD_CARD_2_HIGH) { + CsdSDV2Data = (CSD_SDV2 *)&gCardInfo.CSDData; + + //Populate BlockSize. + *BlockSize = (0x1UL << CsdSDV2Data->READ_BL_LEN); + + //Calculate Total number of blocks. + CardSize = CsdSDV2Data->C_SIZELow16 | (CsdSDV2Data->C_SIZEHigh6 << 2); + *NumBlocks = ((CardSize + 1) * 1024); + } + else if(gCardInfo.CardType == MMC_CARD) + { + //Populate BlockSize. + *BlockSize = (0x1UL << gCardInfo.CSDData.READ_BL_LEN); + + //Calculate Total number of blocks. + CardSize = gCardInfo.CSDData.C_SIZELow2 | (gCardInfo.CSDData.C_SIZEHigh10 << 2); + *NumBlocks = (CardSize + 1) * (1 << (gCardInfo.CSDData.C_SIZE_MULT + 2)); + *NumBlocks *= (*BlockSize); + } + + //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes. + if (*BlockSize > 512) { + DEBUG ((EFI_D_INFO, "SDHC::BlockSize:%d\n", *BlockSize)); + *NumBlocks = MultU64x32(*NumBlocks, *BlockSize/2); + *BlockSize = 512; + } + + DEBUG ((EFI_D_INFO, "Card type: 0x%x, BlockSize: 0x%x, NumBlocks: 0x%x\n", gCardInfo.CardType, *BlockSize, *NumBlocks)); +} + + +VOID +GetCardConfigurationData ( + VOID + ) +{ + UINTN BlockSize; + UINTN NumBlocks; + // UINTN ClockFrequencySelect; + + //Calculate BlockSize and Total number of blocks in the detected card. + GetBlockInformation(&BlockSize, &NumBlocks); + gCardInfo.BlockSize = BlockSize; + gCardInfo.NumBlocks = NumBlocks; + +} + +EFI_STATUS +PerformCardIdenfication ( + VOID + ) +{ + EFI_STATUS Status; + UINTN CmdArgument = 0; + UINTN Response = 0; + UINTN RetryCount = 0; + UINTN TempRes0,TempRes1,TempRes2,TempRes3; + BOOLEAN SDCmd8Supported = FALSE; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + //Send CMD0 command. + Status = MSHC_SendCmd (CMD0, CMD0_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "Cmd0 fails.\n")); + return Status; + } + + DEBUG ((EFI_D_INFO, "CMD0 response: %x\n", MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)))); + + //Send CMD8 command. (New v2.00 command for Voltage check) + //Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass. + //MMC & SD1.1 card will fail this command. + CmdArgument = CMD8_ARG; + Status = MSHC_SendCmd (CMD8, CMD8_INT_EN, CmdArgument); + if (Status == EFI_SUCCESS) { + Response = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)); + DEBUG ((EFI_D_INFO, "CMD8 success. CMD8 response: %x\n", Response)); + if (Response != CmdArgument) { + return EFI_DEVICE_ERROR; + } + DEBUG ((EFI_D_INFO, "Card is SD2.0\n")); + SDCmd8Supported = TRUE; //Supports high capacity. + } else { + DEBUG ((EFI_D_INFO, "CMD8 fails. Not an SD2.0 card.\n")); + } + + //Poll till card is busy + while (RetryCount < MAX_RETRY_COUNT) { + //Send CMD55 command. + CmdArgument = 0; + Status = MSHC_SendCmd (CMD55, CMD55_INT_EN, CmdArgument); + if (Status == EFI_SUCCESS) { + DEBUG ((EFI_D_INFO, "CMD55 success. CMD55 response: %x\n", MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)))); + gCardInfo.CardType = SD_CARD; + } else { + DEBUG ((EFI_D_ERROR, "CMD55 fails.\n")); + gCardInfo.CardType = MMC_CARD; + } + + //Send appropriate command for the card type which got detected. + if (gCardInfo.CardType == SD_CARD) { + CmdArgument = ((UINTN *) &(gCardInfo.OCRData))[0]; + + //Set HCS bit. + if (SDCmd8Supported) { + CmdArgument |= HCS; + } + + Status = MSHC_SendCmd (ACMD41, ACMD41_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "ACMD41 fails.\n")); + return Status; + } + ((UINT32 *) &(gCardInfo.OCRData))[0] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)); + DEBUG ((EFI_D_INFO, "SD card detected. ACMD41 OCR: %x\n", ((UINT32 *) &(gCardInfo.OCRData))[0])); + } else if (gCardInfo.CardType == MMC_CARD) { + CmdArgument = 0; + Status = MSHC_SendCmd (CMD1, CMD1_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD1 fails.\n")); + return Status; + } + Response = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)); + DEBUG ((EFI_D_INFO, "MMC card detected. CMD1 response: %x\n", Response)); + + //NOTE: For now, I am skipping this since I only have an SD card. + //Compare card OCR and host OCR (Section 22.6.1.3.2.4) + return EFI_UNSUPPORTED; //For now, MMC is not supported. + } + + //Poll the card until it is out of its power-up sequence. + if (gCardInfo.OCRData.Busy == 1) { + + if (SDCmd8Supported) { + gCardInfo.CardType = SD_CARD_2; + } + + //Card is ready. Check CCS (Card capacity status) bit (bit#30). + //SD 2.0 standard card will response with CCS 0, SD high capacity card will respond with CCS 1. + if (gCardInfo.OCRData.AccessMode & BIT1) { + gCardInfo.CardType = SD_CARD_2_HIGH; + DEBUG ((EFI_D_INFO, "High capacity card.\n")); + } else { + DEBUG ((EFI_D_INFO, "Standard capacity card.\n")); + } + + break; + } + + gBS->Stall(1000); + RetryCount++; + } + + if (RetryCount == MAX_RETRY_COUNT) { + DEBUG ((EFI_D_ERROR, "Timeout error. RetryCount: %d\n", RetryCount)); + return EFI_TIMEOUT; + } + + //Read CID data. + CmdArgument = 0; + Status = MSHC_SendCmd (CMD2, CMD2_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD2 fails. Status: %x\n", Status)); + return Status; + } + + DEBUG ((EFI_D_INFO, "CMD2 response: %x %x %x %x\n", MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)), \ + MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1)), \ + MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2)), \ + MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3)))); + + TempRes0 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)); + TempRes1 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1)); + TempRes2 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2)); + TempRes3 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3)); + + //Parse CID register data. + ParseCardCIDData(TempRes0 << 8, (TempRes1 << 8) | (TempRes0 >> 24), + (TempRes2 << 8) | (TempRes1 >> 24), (TempRes3 << 8) | (TempRes2 >> 24)); + + //Read RCA + CmdArgument = 0; + Status = MSHC_SendCmd (CMD3, CMD3_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD3 fails. Status: %x\n", Status)); + return Status; + } + + //Set RCA for the detected card. RCA is CMD3 response. + gCardInfo.RCA = (MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)) >> 16); + DEBUG ((EFI_D_INFO, "CMD3 response: RCA %x\n", gCardInfo.RCA)); + + gBS->Stall(1000); //Need Debug by wprkfgur + + return EFI_SUCCESS; +} + + +EFI_STATUS +GetCardSpecificData ( + VOID + ) +{ + EFI_STATUS Status; + UINTN CmdArgument; + UINTN TempRes[4],i; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + //Send CMD9 to retrieve CSD. + CmdArgument = gCardInfo.RCA << 16; + Status = MSHC_SendCmd (CMD9, CMD9_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD9 fails. Status: %x\n", Status)); + return Status; + } + + TempRes[0] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)); + TempRes[1] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1)); + TempRes[2] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2)); + TempRes[3] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3)); + + //Populate 128-bit CSD register data. + + for (i = 0 ; i < 4; i++) { + ((UINT32 *)&(gCardInfo.CSDData))[i] = TempRes[i]; + } + + DEBUG ((EFI_D_INFO, "CMD9 response: %x %x %x %x\n", ((UINT32 *)&(gCardInfo.CSDData))[0], ((UINT32 *)&(gCardInfo.CSDData))[1], ((UINT32 *)&(gCardInfo.CSDData))[2], ((UINT32 *)&(gCardInfo.CSDData))[3])); + PrintCardInfo(); + //Calculate total number of blocks and max. data transfer rate supported by the detected card. + GetCardConfigurationData(); + return Status; +} + +EFI_STATUS +PerformCardConfiguration ( + VOID + ) +{ + UINTN CmdArgument = 0; + EFI_STATUS Status; + UINT32 SdMmcBaseAddr; + //UINTN FifoCount = 0; + //UINTN Count=0; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + //Send CMD7 + CmdArgument = gCardInfo.RCA << 16; + Status = MSHC_SendCmd (CMD7, CMD7_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD7 fails. Status: %x\n", Status)); + return Status; + } + + if ((gCardInfo.CardType != UNKNOWN_CARD) && (gCardInfo.CardType != MMC_CARD)) { + // We could read SCR register, but SD Card Phys spec stats any SD Card shall + // set SCR.SD_BUS_WIDTHS to support 4-bit mode, so why bother? + + // Send ACMD6 (application specific commands must be prefixed with CMD55) + Status = MSHC_SendCmd (CMD55, CMD55_INT_EN, CmdArgument); + if (!EFI_ERROR (Status)) { + // set device into 4-bit data bus mode + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, 0x2); + if (!EFI_ERROR (Status)) { + // Set host controler into 4-bit mode + MmioOr32 ((SdMmcBaseAddr + MSHCI_CTYPE), CARD_WIDTH14); + DEBUG ((EFI_D_INFO, "SD Memory Card set to 4-bit mode\n")); + } + } + } + + //Send CMD16 to set the block length + CmdArgument = gCardInfo.BlockSize; + Status = MSHC_SendCmd (CMD16, CMD16_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD16 fails. Status: %x\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ReadBlockData ( + IN EFI_BLOCK_IO_PROTOCOL *This, + OUT VOID *Buffer, + IN UINTN BlockCount + ) +{ + EFI_STATUS Status = EFI_INVALID_PARAMETER; + UINTN DataSize = This->Media->BlockSize/4; + + DEBUG ((EFI_D_INFO, "SDHC::ReadBlockData start \n")); + + if(MSHC_operation_mode == MSHC_FIFO) + { + Status = MSHC_ReadFIFO(DataSize, Buffer); + } + + else if(MSHC_operation_mode == MSHC_IDMA) + { + Status = MSHC_ReadDMA(Buffer, BlockCount); + } + + return Status; +} + + +EFI_STATUS +WriteBlockData ( + IN EFI_BLOCK_IO_PROTOCOL *This, + OUT VOID *Buffer, + IN UINTN BlockCount + ) +{ + EFI_STATUS Status = EFI_INVALID_PARAMETER; + UINTN DataSize = This->Media->BlockSize/4; + + if(MSHC_operation_mode == MSHC_FIFO) + { + Status = MSHC_WriteFIFO(DataSize, Buffer); + } + else if(MSHC_operation_mode == MSHC_IDMA) + { + Status = MSHC_WriteDMA(Buffer, BlockCount); + } + + return Status; +} + + +EFI_STATUS +TransferBlock ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Lba, + IN OUT VOID *Buffer, + IN UINTN BlockCount, + IN OPERATION_TYPE OperationType + ) +{ + EFI_STATUS Status; + UINTN Cmd = 0; + UINTN CmdInterruptEnable = 0; + UINTN CmdArgument = 0; + + // 1. FIFO reset + // MSHC_SendCmd do the fifo reset + + // 2. prepare transfer + + DEBUG ((EFI_D_INFO, "SDHC::TransferBlock : Lba = %d, Buffer = 0x%x, Type = %d\n", Lba, Buffer, OperationType)); + //Populate the command information based on the operation type. + if (OperationType == READ) + { + if(BlockCount>1) + { + Cmd = CMD18; //multi block read + CmdInterruptEnable = CMD18_INT_EN; + } + else + { + Cmd = CMD17; //Single block read + CmdInterruptEnable = CMD17_INT_EN; + } + + } + else if (OperationType == WRITE) + { + if(BlockCount>1) + { + Cmd = CMD25; //multi block write + CmdInterruptEnable = CMD25_INT_EN; + } + else + { + Cmd = CMD24; //Single block write + CmdInterruptEnable = CMD24_INT_EN; + } + } + PrepareTransfer(Buffer, BlockCount, OperationType); + + //Set command argument based on the card access mode (Byte mode or Block mode) + if (gCardInfo.OCRData.AccessMode & BIT1) { + CmdArgument = Lba; + } else { + CmdArgument = Lba * This->Media->BlockSize; + } + + //Send Command. + Status = MSHC_SendCmd (Cmd, CmdInterruptEnable, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD%d fails. Status: %x\n", (Cmd&0x3F), Status)); + return Status; + } + + DEBUG ((EFI_D_INFO, "CMD%d succeed! \n", (Cmd&0x3F))); + + //Read or Write data. + if (OperationType == READ) { + Status = ReadBlockData (This, Buffer, BlockCount); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n")); + return Status; + } + } else if (OperationType == WRITE) { + Status = WriteBlockData (This, Buffer, BlockCount); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n")); + return Status; + } + } + + return EFI_SUCCESS; +} + +BOOLEAN +CardPresent ( + VOID + ) +{ + EXYNOS_GPIO *Gpio; + EFI_STATUS Status; + UINT32 Val; + + Status = gBS->LocateProtocol(&gSamsungPlatformGpioProtocolGuid, NULL, (VOID **)&Gpio); + ASSERT_EFI_ERROR(Status); + + Gpio->Get(Gpio,SD_2_EVT1_CDn,&Val); + + if(Val) + { + //DEBUG((EFI_D_INFO, "SDHC::CardPresent %d\n", Val)); + return FALSE; + } + else + return TRUE; + +} + +EFI_STATUS +DetectCard ( + VOID + ) +{ + EFI_STATUS Status; + //UINT32 SdMmcBaseAddr; + + //DEBUG ((EFI_D_INFO, "===================================\n")); + DEBUG ((EFI_D_INFO, "===SDHC: Version %a ===\n", DateInformation)); + //DEBUG ((EFI_D_INFO, "===================================\n")); + + //SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + if (!CardPresent ()) { + return EFI_NO_MEDIA; + } + + //Initialize MMC host controller clocks. + Status = InitializeMSHC (); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status)); + return Status; + } + + // EVT1 InitializeSDHC do the SW Reset + //Soft reset for all. + //MmioWrite32((SdMmcBaseAddr + SDHC_SWRST_OFFSET), SRA); + //gBS->Stall(1000); + //while ((MmioRead32 ((SdMmcBaseAddr + SDHC_SWRST_OFFSET)) & SRA) != 0x0); + + //Set the clock frequency to 400KHz. + UpdateMSHCClkFrequency (MSHC_CLK_400); + + //Card idenfication + Status = PerformCardIdenfication (); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "No MMC/SD card detected.\n")); + return Status; + } + + //Get CSD (Card specific data) for the detected card. + Status = GetCardSpecificData(); + if (EFI_ERROR(Status)) { + return Status; + } + + //Configure the card in data transfer mode. + Status = PerformCardConfiguration(); + if (EFI_ERROR(Status)) { + return Status; + } + + + //Patch the Media structure. + gSDMMCMedia.LastBlock = (gCardInfo.NumBlocks - 1); + gSDMMCMedia.BlockSize = gCardInfo.BlockSize; + // gSDMMCMedia.BlockSize = 512; + gSDMMCMedia.ReadOnly = 0; + gSDMMCMedia.MediaPresent = TRUE; + gSDMMCMedia.MediaId++; + + UpdateMSHCClkFrequency(MSHC_CLK_25M); + DEBUG ((EFI_D_INFO, "SD Card Media Change on Handle 0x%08x\n", gImageHandle)); + + return Status; +} + + +EFI_STATUS +SdReadWrite ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Lba, + OUT VOID *Buffer, + IN UINTN BufferSize, + IN OPERATION_TYPE OperationType + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN RetryCount = 0; + UINTN BlockCount; + UINTN BytesToBeTranferedThisPass = 0; + UINTN BytesRemainingToBeTransfered=0; + EFI_TPL OldTpl; + BOOLEAN Update; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + Update = FALSE; + + DEBUG ((EFI_D_INFO, "SDHC::SDHCInitialize is called \n")); + if (gMediaChange) { + Update = TRUE; + Status = DetectCard(); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SDHC::SDHCInitialize:Card Detect Fail\n")); + gSDMMCMedia.MediaPresent = FALSE; + gSDMMCMedia.LastBlock = 0; + gSDMMCMedia.BlockSize = 512; // Should be zero but there is a bug in DiskIo + gSDMMCMedia.ReadOnly = FALSE; + } + gMediaChange = FALSE; + } else if (!gSDMMCMedia.MediaPresent) { + Status = EFI_NO_MEDIA; + goto Done; + } + + if (Update) { + DEBUG ((EFI_D_INFO, "SD Card ReinstallProtocolInterface ()\n")); + gBS->ReinstallProtocolInterface ( + gImageHandle, + &gEfiBlockIoProtocolGuid, + &gBlockIo, + &gBlockIo); + } +DEBUG ((EFI_D_INFO, "SDHC::SDHCInitialize:CardInfo : LastBlock = %ld, BlockSize = %d\n", gSDMMCMedia.LastBlock, gSDMMCMedia.BlockSize)); + + + if (Buffer == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (Lba > This->Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((BufferSize % This->Media->BlockSize) != 0) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + //Check if the data lines are not in use. + while ((RetryCount++ < MAX_RETRY_COUNT) && (MmioRead32 ((SdMmcBaseAddr + MSHCI_STATUS)) & DATA_BUSY)); + if (RetryCount == MAX_RETRY_COUNT) { + Status = EFI_TIMEOUT; + DEBUG ((EFI_D_ERROR, "MSHC::SdReadWrite EFI_TIMEOUT\n")); + goto Done; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + BytesRemainingToBeTransfered = BufferSize; + + if(MSHC_operation_mode == MSHC_IDMA) + { + while (BytesRemainingToBeTransfered > 0) { + // Turn OFF DMA path until it is debugged + BytesToBeTranferedThisPass = (BytesRemainingToBeTransfered >= MAX_MSHC_TRANSFER_SIZE) ? MAX_MSHC_TRANSFER_SIZE : BytesRemainingToBeTransfered; + //BytesToBeTranferedThisPass = This->Media->BlockSize; + + BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize; + Status = TransferBlock (This, Lba, Buffer,BlockCount, OperationType); + + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status)); + goto DoneRestoreTPL; + } + + BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass; + Lba += BlockCount; + Buffer = (UINT8 *)Buffer + (This->Media->BlockSize*BlockCount); + DEBUG ((EFI_D_INFO, "SdReadWrite::Buf:0x%x, ToBe:0x%x Rema:0x%x \n", BufferSize, BytesToBeTranferedThisPass, BytesRemainingToBeTransfered)); + } + } + else + { + while (BytesRemainingToBeTransfered > 0) { + // Turn OFF DMA path until it is debugged + // BytesToBeTranferedThisPass = (BytesToBeTranferedThisPass >= MAX_SDHC_TRANSFER_SIZE) ? MAX_SDHC_TRANSFER_SIZE : BytesRemainingToBeTransfered; + BytesToBeTranferedThisPass = This->Media->BlockSize; + + BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize; + + if (BlockCount > 1) { + // Status = DmaBlocks (This, Lba, Buffer, BlockCount, OperationType); + } else { + //Transfer a block worth of data. + Status = TransferBlock (This, Lba, Buffer, BlockCount,OperationType); + + } + + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status)); + goto DoneRestoreTPL; + } + + BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass; + Lba += BlockCount; + Buffer = (UINT8 *)Buffer + This->Media->BlockSize; + } + + } + + +DoneRestoreTPL: + + gBS->RestoreTPL (OldTpl); + +Done: + return Status; + +} + + +/** + + Reset the Block Device. + + + + @param This Indicates a pointer to the calling context. + + @param ExtendedVerification Driver may perform diagnostics on reset. + + + + @retval EFI_SUCCESS The device was reset. + + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + + not be reset. + + + +**/ +EFI_STATUS +EFIAPI +MSHCReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + DEBUG ((EFI_D_INFO, " MSHC::MSHCReset is called\n")); + MSHC_reset_all(); + return EFI_SUCCESS; +} + + +/** + + Read BufferSize bytes from Lba into Buffer. + + + + @param This Indicates a pointer to the calling context. + + @param MediaId Id of the media, changes every time the media is replaced. + + @param Lba The starting Logical Block Address to read from + + @param BufferSize Size of Buffer, must be a multiple of device block size. + + @param Buffer A pointer to the destination buffer for the data. The caller is + + responsible for either having implicit or explicit ownership of the buffer. + + + + @retval EFI_SUCCESS The data was read correctly from the device. + + @retval EFI_DEVICE_ERROR The device reported an error while performing the read. + + @retval EFI_NO_MEDIA There is no media in the device. + + @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device. + + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + + or the buffer is not on proper alignment. + +EFI_STATUS + +**/ + + +#define EMMC_TEST 0 +#if EMMC_TEST +#define EMMC_TEST_SIZE (512*2)//(MAX_MSHC_TRANSFER_SIZE+1024) +UINT32 bWrite[EMMC_TEST_SIZE]; +UINT32 bRead[EMMC_TEST_SIZE]; +//INTN EFIAPI CompareMem (IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length) +//two buffers are identical, then 0 is returned. Otherwise, the value returned is the first mismatched byte + +void MSHC_Test( IN EFI_BLOCK_IO_PROTOCOL *This) +{ + UINTN i=0; + UINTN Count; + INTN ret; + EFI_STATUS Status; + DEBUG ((EFI_D_INFO, "MSHC::Read Write test %dB\n", EMMC_TEST_SIZE)); + + for(i=0; i<EMMC_TEST_SIZE; i++) + { + bWrite[i]=i; + } + +//multi + for(Count=100000; Count<100002; Count++) + { + //Lba=n; + //DEBUG ((EFI_D_INFO, "MSHC::Read Write test : %d\n", Count)); + ZeroMem (&bRead[0], sizeof(bRead)); + DEBUG ((EFI_D_INFO, "ZR : 0x%x, 0x%x, 0x%x, 0x%x\n", + bRead[0], bRead[1], bRead[2], bRead[3])); + + Status = SdReadWrite (This, (UINTN)Count, &bWrite[0], EMMC_TEST_SIZE, WRITE); + Status = SdReadWrite (This, (UINTN)Count, &bRead[0], EMMC_TEST_SIZE, READ); + + DEBUG ((EFI_D_INFO, "W: 0x%x, 0x%x, 0x%x, 0x%x ", + bWrite[0], bWrite[1], bWrite[2], bWrite[3])); + DEBUG ((EFI_D_INFO, "R : 0x%x, 0x%x, 0x%x, 0x%x\n", + bRead[0], bRead[1], bRead[2], bRead[3])); + + ret = CompareMem(&bRead[0],&bWrite[0],EMMC_TEST_SIZE); + + if(ret==0) + DEBUG ((1, "SDHC::Read Write OK!!\n\n")); + else + DEBUG ((1, "SDHC::Read Write Failed bWrite[%d]=0x%x : bRead[%d]=0x%x\n", ret, bWrite[ret], ret, bRead[ret])); + + + } + + +} +#endif + +EFI_STATUS +EFIAPI +MSHCReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status=EFI_SUCCESS; + DEBUG ((EFI_D_INFO, "SDHC::MSHCReadBlocks : MediaId = %x, Lba = %d, BufferSize = %d, Buffer = 0x%x\n", + MediaId, (UINTN)Lba, BufferSize, Buffer)); + +#if EMMC_TEST + MSHC_Test(This); +#else + //Perform Read operation. + Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ); +#endif + return Status; + +} + + +/** + + Write BufferSize bytes from Lba into Buffer. + + + + @param This Indicates a pointer to the calling context. + + @param MediaId The media ID that the write request is for. + + @param Lba The starting logical block address to be written. The caller is + + responsible for writing to only legitimate locations. + + @param BufferSize Size of Buffer, must be a multiple of device block size. + + @param Buffer A pointer to the source buffer for the data. + + + + @retval EFI_SUCCESS The data was written correctly to the device. + + @retval EFI_WRITE_PROTECTED The device can not be written to. + + @retval EFI_DEVICE_ERROR The device reported an error while performing the write. + + @retval EFI_NO_MEDIA There is no media in the device. + + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. + + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + + or the buffer is not on proper alignment. + + + +**/ + + +EFI_STATUS +EFIAPI +MSHCWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; +#if EMMC_TEST + UINT32 Count=0; + UINT32 ret; +#endif + + DEBUG ((EFI_D_INFO, "SDHC::MSHCWriteBlocks : MediaId = 0x%x, Lba = %d, BufferSize = %d, Buffer = 0x%x\n", + MediaId, (UINTN)Lba, BufferSize, Buffer)); + + //Perform write operation. + Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, WRITE); + +#if EMMC_TEST + Count = (BufferSize >= MAX_MSHC_TRANSFER_SIZE) ? MAX_MSHC_TRANSFER_SIZE : BufferSize; + DEBUG ((1, "\nMSHC::Read Write Test [0x%x] Start \n", Count)); + ZeroMem (&bRead[0], sizeof(bRead)); + CopyMem(&bWrite[0], (VOID *)Buffer, Count); + Status = SdReadWrite (This, (UINTN)Lba, &bRead[0], Count, READ); + DEBUG ((1, "W : 0x%x, 0x%x, 0x%x, 0x%x\n", + bWrite[7], bWrite[8], bWrite[9], bWrite[10])); + + DEBUG ((1, "R : 0x%x, 0x%x, 0x%x, 0x%x\n", + bRead[7], bRead[8], bRead[9], bRead[10])); + + ret = CompareMem(&bRead[0],&bWrite[0],Count); + + if(ret==0) + DEBUG ((1, "SDHC::Read Write Test OK!!\n")); + else + DEBUG ((1, "SDHC::Read Write Test Failed -.- bRead[%d]=0x%x bWrite[%d]=0x%x \n", ret, bRead[ret], ret, bWrite[ret])); + +#endif + + return Status; + +} + + +/** + + Flush the Block Device. + + + + @param This Indicates a pointer to the calling context. + + + + @retval EFI_SUCCESS All outstanding data was written to the device + + @retval EFI_DEVICE_ERROR The device reported an error while writting back the data + + @retval EFI_NO_MEDIA There is no media in the device. + + + +**/ +EFI_STATUS +EFIAPI +MSHCFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + DEBUG ((EFI_D_INFO, "SDHC::MSHCFlushBlocks is called\n")); + return EFI_SUCCESS; +} + + +EFI_BLOCK_IO_PROTOCOL gBlockIo = { + EFI_BLOCK_IO_INTERFACE_REVISION, // Revision + &gSDMMCMedia, // *Media + MSHCReset, // Reset + MSHCReadBlocks, // ReadBlocks + MSHCWriteBlocks, // WriteBlocks + MSHCFlushBlocks // FlushBlocks +}; + +/** + + Timer callback to convert card present hardware into a boolean that indicates + + a media change event has happened. If you just check the GPIO you could see + + card 1 and then check again after card 1 was removed and card 2 was inserted + + and you would still see media present. Thus you need the timer tick to catch + + the toggle event. + + + + @param Event Event whose notification function is being invoked. + + @param Context The pointer to the notification function's context, + + which is implementation-dependent. Not used. + + + +**/ +VOID +EFIAPI +TimerCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + BOOLEAN Present; + + //DEBUG ((EFI_D_ERROR, "SDHC::TimerCallBack is called\n")); + Present = CardPresent (); + if (gSDMMCMedia.MediaPresent) { + if (!Present && !gMediaChange) { + gMediaChange = TRUE; + } + } else { + if (Present && !gMediaChange) { + gMediaChange = TRUE; + } + } +} + +EFI_HANDLE mHandle = NULL; +EFI_EVENT mCommandProtocolRegistration=NULL; + +VOID +EFIAPI +CommandProtocolNotificationEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + if(mHandle!=NULL){ + return; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHandle, + &gEfiBlockIoProtocolGuid, &gBlockIo, + &gEfiDevicePathProtocolGuid, &gMSHCDevicePath, + NULL + ); + DEBUG((EFI_D_INFO, "SDHC::install protocol \n" )); + if(Status!=EFI_SUCCESS) + { + DEBUG((EFI_D_ERROR, "SDHC::install protocol fail %r\n", Status)); + } +} + + + +EFI_STATUS +EFIAPI +SDHCInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + ZeroMem (&gCardInfo, sizeof (CARD_INFO)); + + Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, TimerCallback, NULL, &gTimerEvent); + ASSERT_EFI_ERROR (Status); + + Status = gBS->SetTimer (gTimerEvent, TimerPeriodic, 1000000); + ASSERT_EFI_ERROR (Status); + + EfiCreateProtocolNotifyEvent ( + &gEfiEblAddCommandProtocolGuid, + TPL_CALLBACK, + CommandProtocolNotificationEvent, + (VOID *)SystemTable, + &mCommandProtocolRegistration + ); + +#if 0 + //Publish BlockIO. + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiBlockIoProtocolGuid, &gBlockIo, + &gEfiDevicePathProtocolGuid, &gMSHCDevicePath, + NULL + ); +#endif + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.h new file mode 100755 index 000000000..29f317b19 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.h @@ -0,0 +1,259 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _MSHCDXE_H_ +#define _MSHCDXE_H_ + +#include <Uefi.h> + +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseMemoryLib.h> +#include <Protocol/BlockIo.h> +#include <Protocol/DevicePath.h> +#include <Protocol/EblAddCommand.h> +#include <Library/UefiLib.h> + +#include "SDHCDxe_5250.h" +#include "SDHCDxe_CMD.h" + + +#define MSHC_BOOT_SIZE 100 //100M +#define MSHC_RPMB_SIZE 0 + +#define MSHC_EMMC_OCR 0xC0FF8080 + +#define BLEN_512BYTES (0x200) +#define BLKSIZE_1 (0x1) + + +#define MAX_RETRY_COUNT (100000) +#define MMC_REFERENCE_CLK (96000000) +#define MSHC_CLK_400 (400) +#define MSHC_CLK_25M (25000) +#define MSHC_CLK_50M (50000) + +#define OCR_BUSY 0x80000000 +#define OCR_HCS 0x40000000 + +#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ +#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ +#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ +#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ +#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ +#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ +#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ +#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ +#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ +#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ +#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ +#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ +#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ +#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ +#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ +#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ +#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ + + +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in EXT_CSD byte + addressed by index which are + 1 in value field */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in EXT_CSD byte + addressed by index, which are + 1 in value field */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target byte to value */ +/* + * EXT_CSD fields + */ + +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define BOOT_SIZE_MULTI 226 /* RO */ + +/* + * EXT_CSD field definitions + */ + +/* Card */ +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ +#define EXT_CSD_CARD_TYPE_52_DDR_18_30 (1<<2) /* Card can run at 52MHz DDR 1.8V or 3V */ +#define EXT_CSD_CARD_TYPE_52_DDR_12 (1<<3) /* Card can run at 52MHz DDR 1.2V */ + +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ +#define EXT_CSD_BUS_WIDTH_4_DDR 5 /* Card is in 4 bit DDR mode */ +#define EXT_CSD_BUS_WIDTH_8_DDR 6 /* Card is in 8 bit DDR mode */ + + +typedef struct { + UINT32 hs_max_dtr; + UINT32 sectors; + UINT32 boot_size_multi; +}mmc_ext_csd; + + +typedef struct { + UINT32 Reserved0: 7; // 0 + UINT32 V170_V195: 1; // 1.70V - 1.95V + UINT32 V200_V260: 7; // 2.00V - 2.60V + UINT32 V270_V360: 9; // 2.70V - 3.60V + UINT32 RESERVED_1: 5; // Reserved + UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode) + UINT32 Busy: 1; // This bit is set to LOW if the card has not finished the power up routine +}OCR; + +typedef struct { + UINT32 NOT_USED; // 1 [0:0] + UINT32 CRC; // CRC7 checksum [7:1] + UINT32 MDT; // Manufacturing date [19:8] + UINT32 RESERVED_1; // Reserved [23:20] + UINT32 PSN; // Product serial number [55:24] + UINT8 PRV; // Product revision [63:56] + UINT8 PNM[5]; // Product name [64:103] + UINT16 OID; // OEM/Application ID [119:104] + UINT8 MID; // Manufacturer ID [127:120] +}CID; + +typedef struct { + UINT8 NOT_USED: 1; // Not used, always 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] + + UINT8 RESERVED_1: 2; // Reserved [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + + UINT16 RESERVED_2: 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 RESERVED_3: 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + + UINT32 WP_GRP_SIZE: 7; // Write protect group size [38:32] + UINT32 SECTOR_SIZE: 7; // Erase sector size [45:39] + UINT32 ERASE_BLK_EN: 1; // Erase single block enable [46:46] + UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47] + UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50] + UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53] + UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56] + UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59] + UINT32 C_SIZELow2: 2; // Device size [63:62] + + UINT32 C_SIZEHigh10: 10;// Device size [73:64] + UINT32 RESERVED_4: 2; // Reserved [75:74] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT32 CCC: 12;// Card command classes [95:84] + + UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96] + UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC ; // Data read access-time 1 [119:112] + + UINT8 RESERVED_5: 6; // Reserved [125:120] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +}CSD; + + + +typedef struct { + UINT8 NOT_USED: 1; // Not used, always 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] + UINT8 RESERVED_1: 2; // Reserved [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + UINT16 RESERVED_2: 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 RESERVED_3: 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + UINT16 WP_GRP_SIZE: 7; // Write protect group size [38:32] + UINT16 SECTOR_SIZE: 7; // Erase sector size [45:39] + UINT16 ERASE_BLK_EN: 1; // Erase single block enable [46:46] + UINT16 RESERVED_4: 1; // Reserved [47:47] + UINT32 C_SIZELow16: 16;// Device size [69:48] + UINT32 C_SIZEHigh6: 6; // Device size [69:48] + UINT32 RESERVED_5: 6; // Reserved [75:70] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + UINT16 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT16 CCC: 12;// Card command classes [95:84] + UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96] + UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC ; // Data read access-time 1 [119:112] + UINT8 RESERVED_6: 6; // 0 [125:120] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +}CSD_SDV2; + +typedef enum { + UNKNOWN_CARD, + MMC_CARD, //MMC card + SD_CARD, //SD 1.1 card + SD_CARD_2, //SD 2.0 or above standard card + SD_CARD_2_HIGH, //SD 2.0 or above high capacity card + SD_CARD_MAX +} CARD_TYPE; + + + +typedef enum { + MSHC_IDMA, + MSHC_FIFO +}MSHC_OPERATION_MODE; + +typedef struct { + UINT16 RCA; + UINTN BlockSize; + UINTN NumBlocks; + UINTN ClockFrequencySelect; + CARD_TYPE CardType; + OCR OCRData; + CID CIDData; + CSD CSDData; +} CARD_INFO; + + +EFI_STATUS +DetectCard (VOID); +void mshci_reset_fifo(void); + +extern EFI_BLOCK_IO_PROTOCOL gBlockIo; + +#endif + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.inf new file mode 100755 index 000000000..167eee6a4 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe.inf @@ -0,0 +1,58 @@ +#/** @file +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SDHCDxe + FILE_GUID = 7B857F59-CD4D-4403-A866-CFAD3A7C1381 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = SDHCInitialize + + +[Sources.common] + SDHCDxe.c + SDHCDxe_5250.c + +[Packages] + MdePkg/MdePkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + SamsungPlatformPkg/SamsungPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + IoLib + TimerLib + MemoryAllocationLib + UefiLib + +[Guids] + +[Protocols] + gEfiBlockIoProtocolGuid + gEfiDevicePathProtocolGuid + gSamsungPlatformGpioProtocolGuid ## GPIO Protocol + gEfiEblAddCommandProtocolGuid + + +[Pcd] + gExynosPkgTokenSpaceGuid.PcdCmuBase + gExynosPkgTokenSpaceGuid.PcdSdMmcBase + gExynosPkgTokenSpaceGuid.PcdEmmcDMABufferBase + +[Depex] + TRUE + + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_5250.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_5250.c new file mode 100755 index 000000000..5408360b0 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_5250.c @@ -0,0 +1,658 @@ +/** @file + MMC/SD Card driver for Secure Digital Host Controller + + This driver always produces a BlockIo protocol but it starts off with no Media + present. A TimerCallBack detects when media is inserted or removed and after + a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the + media to be detected (or removed) and the BlockIo Media structure will get + updated. No MMC/SD Card harward registers are updated until the first BlockIo + ReadBlocks/WriteBlocks after media has been insterted (booting with a card + plugged in counts as an insertion event). + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + + +#include <Library/TimerLib.h> +#include <Library/PcdLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Protocol/ExynosGpio.h> +#include <Platform/ArmPlatform.h> +#include <Platform/Exynos5250.h> +#include <Platform/Arndale5250.h> + + +#include "SDHCDxe.h" + +//#undef EFI_D_INFO +//#define EFI_D_INFO 1 + + + +void MSHC_reset_all(void) +{ + int count; + volatile int ctl_val=0; + UINT32 SdMmcBaseAddr; + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + /* Wait max 100 ms */ + count = 10000; + + /* before reset ciu, it should check DATA0. if when DATA0 is low and + it resets ciu, it might make a problem */ + while ((MmioRead32 ((SdMmcBaseAddr + MSHCI_STATUS)) & (1<<9))){ + if (count == 0) { + DEBUG ((EFI_D_ERROR, "MMC controller never released. \n")); + return; + } + count--; + MicroSecondDelay(1); + } + + // Reset CIU + ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL)); + ctl_val |= CTRL_RESET; + MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val); + + //Reset FIFO + MSHC_reset_fifo(); + + //Reset DMA + ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL)); + ctl_val |= DMA_RESET; + MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val); + + //Set auto stop CMD + ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL)); + ctl_val |= SEND_AS_CCSD; + MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val); + +} + + +void MSHC_Set_DDR(int BusMode) +{ + + UINT32 clkphase; + //clkphase = 0x03030002; //cmd response error at 50M RINT=0x46 error, RE and CD, RCRC + //clkphase = 0x03020001; //data read error at 50M SBE + UINT32 SdMmcBaseAddr; + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + if(BusMode==BUSMODE_DDR) + { + DEBUG ((EFI_D_INFO, "MSHC DDR .\n")); + MmioWrite32((SdMmcBaseAddr + MSHCI_UHS_REG), UHS_DDR); + clkphase = 0x03020001; + } + else + { + DEBUG ((EFI_D_INFO, "MSHC Non DDR .\n")); + MmioWrite32((SdMmcBaseAddr + MSHCI_UHS_REG), UHS_NON_DDR); + clkphase = 0x03030002; + } + MmioWrite32((SdMmcBaseAddr + MSHCI_CLKSEL), clkphase); + +} + + +void MSHC_5250_init(void) +{ + UINT32 SdMmcBaseAddr; + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + /* Power Enable Register */ + MmioWrite32((SdMmcBaseAddr + MSHCI_PWREN), POWER_ENABLE); + //MSHC_Set_DDR(BUSMODE_DDR); + + MSHC_reset_all(); + + // Initialize FIFO + MmioWrite32((SdMmcBaseAddr + MSHCI_FIFOTH), (MSIZE_8 | TX_WMARK_DEFAULT | RX_WMARK_DEFAULT)); + + /* It clears all pending interrupts */ + MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_ALL); + /* It dose not use Interrupt. Disable all */ + MmioWrite32((SdMmcBaseAddr + MSHCI_INTMSK), 0); + + //UpdateMSHCClkFrequency(MSHC_CLK_400); + + /* Set auto stop command */ + //MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), (1<<10)); + + /* set debounce filter value*/ + MmioWrite32((SdMmcBaseAddr + MSHCI_DEBNCE), (0xfffff)); + + /* clear card type. set 1-bit mode */ + MmioWrite32((SdMmcBaseAddr + MSHCI_CTYPE), 0x0); + + /* set bus mode register for IDMAC */ + MmioWrite32((SdMmcBaseAddr + MSHCI_BMOD), (BMOD_IDMAC_RESET)); + + /* disable all interrupt source of IDMAC */ + MmioWrite32((SdMmcBaseAddr + MSHCI_IDINTEN), (0x0)); + + /* set max timeout */ + MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff)); + + MmioWrite32((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES); + MmioWrite32((SdMmcBaseAddr + MSHCI_CLKSEL), 0x03030002); + +} + +EFI_STATUS +InitializeMSHC ( + VOID + ) +{ + + EFI_STATUS Status; + EXYNOS_GPIO *Gpio; + UINT32 CumBaseAddr; + //UINT32 SdMmcBaseAddr; + UINT32 i, clock; + volatile UINT32 ctl_val; + + + Status = gBS->LocateProtocol(&gSamsungPlatformGpioProtocolGuid, NULL, (VOID **)&Gpio); + ASSERT_EFI_ERROR(Status); + + CumBaseAddr = PcdGet32(PcdCmuBase); + //SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + //MmioWrite32((SdMmcBaseAddr + SDHC_SWRST_OFFSET), SRA); + + // Set Clock Source for using MPLL + ctl_val = MmioRead32((CumBaseAddr + CLK_SRC_FSYS_OFFSET)); + ctl_val &= ~(0xf<<8); + ctl_val |= (0x6<<8); + MmioWrite32((CumBaseAddr + CLK_SRC_FSYS_OFFSET), ctl_val); + //MmioAndThenOr32 ((CumBaseAddr + CLK_SRC_FSYS_OFFSET), ~(0xF), (0x6)); + + // CLK mask + ctl_val = MmioRead32((CumBaseAddr + CLK_SRC_MASK_FSYS_OFFSET)); + ctl_val |= (0x1<<8); + MmioWrite32((CumBaseAddr + CLK_SRC_MASK_FSYS_OFFSET), ctl_val); + + // CLK gating + ctl_val = MmioRead32((CumBaseAddr + CLK_GATE_IP_FSYS_OFFSET)); + ctl_val |= (0x1<<14); + MmioWrite32((CumBaseAddr + CLK_GATE_IP_FSYS_OFFSET), ctl_val); + + + /* MMC2 clock div */ + clock = 800; //MPLL in MHz + for(i=0; i<= 0xf; i++) + { + if((clock / (i+1)) <= 90) { + MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS2_OFFSET), ~(0xF << 0), (i << 0)); + break; + } + } + + + // 2. GPIO setting + // Set GPIO for using SDMMC2 + Gpio->Set(Gpio,SD_2_EVT1_CLK,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_2_EVT1_CMD,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_2_EVT1_CDn,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_2_EVT1_DATA0,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_2_EVT1_DATA1,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_2_EVT1_DATA2,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_2_EVT1_DATA3,GPIO_MODE_SPECIAL_FUNCTION_2); + + Gpio->SetPull(Gpio,SD_2_EVT1_CLK,GPIO_PULL_NONE); + Gpio->SetPull(Gpio,SD_2_EVT1_CMD,GPIO_PULL_NONE); + Gpio->SetPull(Gpio,SD_2_EVT1_CDn,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_2_EVT1_DATA0,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_2_EVT1_DATA1,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_2_EVT1_DATA2,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_2_EVT1_DATA3,GPIO_PULL_UP); + + Gpio->SetStrength(Gpio,SD_2_EVT1_CLK,GPIO_DRV_4X); + Gpio->SetStrength(Gpio,SD_2_EVT1_CMD,GPIO_DRV_4X); + Gpio->SetStrength(Gpio,SD_2_EVT1_CDn,GPIO_DRV_4X); + Gpio->SetStrength(Gpio,SD_2_EVT1_DATA0,GPIO_DRV_4X); + Gpio->SetStrength(Gpio,SD_2_EVT1_DATA1,GPIO_DRV_4X); + Gpio->SetStrength(Gpio,SD_2_EVT1_DATA2,GPIO_DRV_4X); + Gpio->SetStrength(Gpio,SD_2_EVT1_DATA3,GPIO_DRV_4X); + + MSHC_5250_init(); + return EFI_SUCCESS; +} + +void MSHC_reset_fifo(void) +{ + volatile int ctl_val=0; + UINT32 SdMmcBaseAddr; + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + //Reset FIFO + ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL)); + ctl_val |= FIFO_RESET; + MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val); + +} + + +VOID MSHC_clock_onoff (int value) +{ + volatile UINT32 loop_count = 0x100000; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + if(value==CLK_ENABLE) + { + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKENA), (0x1<<0)); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), 0); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK); + do { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_CMD) & CMD_STRT_BIT)==0) + break; + loop_count--; + } while (loop_count); + } + else + { + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKENA), (0x0<<0)); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), 0); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK); + do { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_CMD) & CMD_STRT_BIT)==0) + break; + loop_count--; + } while (loop_count); + } + + if (loop_count == 0) { + DEBUG ((EFI_D_ERROR, "MSHC::clockonoff : Clk = %d\n", value)); + } + +} + + +VOID +UpdateMSHCClkFrequency ( + UINTN NewCLK + ) +{ + UINT32 CumBaseAddr; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + CumBaseAddr = PcdGet32(PcdCmuBase); + + // Disable all clocks to not provide the clock to the card +//(CONFIG_CPU_EXYNOS5250_EVT1) + MSHC_clock_onoff(CLK_DISABLE); + //MmioAnd32 ((SdMmcBaseAddr + CLKCON_OFFSET), ~(0xF)); + + //Set new clock frequency. + if (NewCLK == MSHC_CLK_400) + { + DEBUG ((EFI_D_INFO, "MSHC::CLK=400.\n")); + // MPLL=800, cclk_in=100, 100M/250=400k + //MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0xE008); + MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS2_OFFSET), ~(0xFFFF), 0x1); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 125); + } + else if (NewCLK == MSHC_CLK_25M) + { + DEBUG ((EFI_D_INFO, "MSHC::CLK=25M.\n")); + // DDR mode use CLKDIV MPLL = 800, SCLK = 400, cclk_in=100M + //MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS2_OFFSET), ~(0xFFFF), 0x1); + //MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 2); + MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS2_OFFSET), ~(0xFFFF), 0x1); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 2); + } + else if(NewCLK == MSHC_CLK_50M) + { + DEBUG ((EFI_D_INFO, "MSHC::CLK=50M.\n")); + // DDR mode use CLKDIV MPLL = 800, SCLK = 400, cclk_in=100M + MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS2_OFFSET), ~(0xFFFF), 0x1); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 1); + + MSHC_Set_DDR(BUSMODE_DDR); + //MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK); + } + +//#if defined(CONFIG_CPU_EXYNOS5250_EVT1) + MSHC_clock_onoff(CLK_ENABLE); + //MmioOr32 ((SdMmcBaseAddr + CLKCON_OFFSET), ICE); + + //Poll till Internal Clock Stable + //while ((MmioRead32 ((SdMmcBaseAddr + CLKCON_OFFSET)) & ICS) != ICS); + + //Set Clock enable to 0x1 to provide the clock to the card + //MmioOr32 ((SdMmcBaseAddr + CLKCON_OFFSET), CCE); + +} + +extern MSHC_OPERATION_MODE MSHC_operation_mode; +void mshci_set_mdma_desc(UINT8 *desc_vir, UINT8 *desc_phy, + UINT32 des0, UINT32 des1, UINT32 des2) +{ + ((struct mshci_idmac *)(desc_vir))->des0 = des0; + ((struct mshci_idmac *)(desc_vir))->des1 = des1; + ((struct mshci_idmac *)(desc_vir))->des2 = des2; + ((struct mshci_idmac *)(desc_vir))->des3 = (UINT32)desc_phy + + sizeof(struct mshci_idmac); +} + + +VOID +PrepareTransfer ( +IN OUT VOID *Buffer, UINTN BlockCount, IN OPERATION_TYPE OperationType + ) +{ + UINT32 SdMmcBaseAddr; + UINT32 EmmcDMABufferBase; + volatile UINT32 MshcRegValue; + struct mshci_idmac *pdesc_dmac; + UINT32 des_flag; + UINTN i=0; + UINT32 ByteCnt=0; + UINT32 BlockCnt=BlockCount; +// UINT32 MSH_uDES_A_0, MSH_uDES_A_1, MSH_uDES_A_2, MSH_uDES_A_3; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + EmmcDMABufferBase = PcdGet32(PcdEmmcDMABufferBase); + EmmcDMABufferBase += PHY_CH2_OFFSET; + DEBUG ((EFI_D_INFO, "EmmcDMABufferBase:0x%x \n", EmmcDMABufferBase)); + pdesc_dmac = (struct mshci_idmac *)EmmcDMABufferBase; + + if(MSHC_operation_mode==MSHC_FIFO) + { + MSHC_reset_fifo(); + + // 1. enable interrupt mode + MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_CTRL); + MshcRegValue |= INT_ENABLE; + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CTRL), MshcRegValue); + + // 2. DDR mode + + // 3. set BLKSIZE + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES); + //MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLKSIZE_1); + + // 4. set BYTCNT + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BYTCNT), BLEN_512BYTES); + + //Setting Data timeout counter value to max value. + MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff)); + + } + else if(MSHC_operation_mode==MSHC_IDMA) + { + ZeroMem ((VOID *)EmmcDMABufferBase, PHY_BUF_OFFSET);//20120608 + if(OperationType==WRITE) + { + CopyMem((VOID *)(EmmcDMABufferBase+PHY_BUF_OFFSET), (VOID *)Buffer, BlockCount*BLEN_512BYTES); + //DEBUG ((EFI_D_INFO, "MSHC_DMA prepare WRITE:%d Block \n", BlockCount)); + } + else + { + //DEBUG ((EFI_D_INFO, "MSHC_DMA prepare READ:%d Block \n", BlockCount)); + } + + MSHC_reset_fifo(); + + //IDMA reset + MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_BMOD); + MshcRegValue |= (BMOD_IDMAC_RESET); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BMOD), MshcRegValue); + + + // 1. enable IDMA at CTRL + MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_CTRL); + MshcRegValue &= ~(INT_ENABLE); + MshcRegValue |= (ENABLE_IDMAC); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CTRL), MshcRegValue); + + + // 2. enable IDMA at BMODE + //Set Block Size and Block count. + MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_BMOD); + MshcRegValue |= (BMOD_IDMAC_ENABLE | BMOD_IDMAC_FB); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BMOD), MshcRegValue); + + // interrupt enable + MmioWrite32((SdMmcBaseAddr + MSHCI_IDINTEN), (0x337)); + + for(i=0; ; i++) + { + // set descriptor multichain + des_flag = (MSHCI_IDMAC_OWN|MSHCI_IDMAC_CH); + des_flag |= (i==0) ? MSHCI_IDMAC_FS:0; + if(BlockCnt<=8) + { + //DEBUG ((EFI_D_INFO, "DESC LD\n")); + des_flag |= (MSHCI_IDMAC_LD); + mshci_set_mdma_desc((UINT8 *)pdesc_dmac, + //(UINT8 *)pdesc_dmac, + (UINT8 *)(EmmcDMABufferBase-sizeof(struct mshci_idmac)), + des_flag, BlockCnt*BLEN_512BYTES, + ((UINT32)((EmmcDMABufferBase + PHY_BUF_OFFSET)+(UINT32)(i*PHY_BUF_SIZE)))); + break; + + } + //DEBUG ((EFI_D_INFO, "DESC FS\n")); + mshci_set_mdma_desc((UINT8 *)pdesc_dmac, + (UINT8 *)pdesc_dmac, + des_flag, BLEN_512BYTES*8, + ((UINT32)((EmmcDMABufferBase + PHY_BUF_OFFSET)+(UINT32)(i*PHY_BUF_SIZE)))); + + BlockCnt -=8; + pdesc_dmac++; + + } + + MmioWrite32 ((SdMmcBaseAddr + MSHCI_DBADDR), (UINT32)EmmcDMABufferBase); + + // 3. set BLKSIZE + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES); + + // 4. set BYTCNT + ByteCnt = (BlockCount*BLEN_512BYTES); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BYTCNT), ByteCnt); + + //Setting Data timeout counter value to max value. + MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff)); + DEBUG ((EFI_D_INFO, "Block:%d BYTCNT:0x%x ByteCnt:0x%x\n", BlockCount,MmioRead32(SdMmcBaseAddr + MSHCI_BYTCNT), ByteCnt)); + + } + +} + +EFI_STATUS MSHC_ReadFIFO(IN UINTN Size32, OUT VOID *Buffer) +{ + EFI_STATUS Status; + UINT32 SdMmcBaseAddr; + UINTN *DataBuffer = Buffer; + UINTN BufSize=Size32; + UINTN FifoCount=0; + UINTN Count=0; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + //Check controller status to make sure there is no error. + + while (BufSize) + { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_RXDR) + { + + //Read block worth of data. + FifoCount = GET_FIFO_COUNT(MmioRead32 (SdMmcBaseAddr + MSHCI_STATUS)); + DEBUG ((EFI_D_INFO, "MSHC::ReadBlock DTO FIFO:%d\n", FifoCount)); + for (Count = 0; Count < FifoCount; Count++) + { + *DataBuffer++ = MmioRead32 (SdMmcBaseAddr + MSHCI_FIFO); + } + MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_RXDR); + BufSize -= FifoCount; + } + + else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO) + { + + //Read block worth of data. + FifoCount = GET_FIFO_COUNT(MmioRead32 (SdMmcBaseAddr + MSHCI_STATUS)); + DEBUG ((EFI_D_INFO, "MSHC::ReadBlock DTO FIFO:%d\n", FifoCount)); + for (Count = 0; Count < FifoCount; Count++) + { + *DataBuffer++ = MmioRead32 (SdMmcBaseAddr + MSHCI_FIFO); + } + MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_DTO); + BufSize -= FifoCount; + } + + else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & (INTMSK_DCRC|INTMSK_DRTO|INTMSK_HTO|INTMSK_FRUN)) + { + DEBUG ((EFI_D_INFO, "MSHC::ReadBlock Error RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS))); + return EFI_DEVICE_ERROR; + } + + } + + if(BufSize==0) + { + Status = EFI_SUCCESS; + } + else + { + Status = EFI_BAD_BUFFER_SIZE; + } + return Status; +} + +EFI_STATUS MSHC_WriteFIFO(IN UINTN Size32, IN VOID *Buffer) +{ + UINT32 SdMmcBaseAddr; + UINTN *DataBuffer = Buffer; + UINTN BufSize=Size32; + UINTN Count=0; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + + if(BufSize>FIFO_SIZE) + { + DEBUG ((EFI_D_INFO, "MSHC::Error MSHC_WriteFIFO Bad buffer size\n")); + return EFI_BAD_BUFFER_SIZE; + } + + //Write block worth of data. + for (Count = 0; Count < BufSize; Count++) + { + MmioWrite32 ((SdMmcBaseAddr + MSHCI_FIFO), *DataBuffer++); + } + return EFI_SUCCESS; + +} + +/*typedef +VOID +CopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + );*/ + +EFI_STATUS MSHC_ReadDMA(OUT VOID *Buffer, IN UINTN BlockCount) +{ + EFI_STATUS Status; + UINT32 SdMmcBaseAddr, EmmcDMABufferBase; + UINTN Count=MAX_RETRY_COUNT; + //UINT32 MshcRegValue; + //UINT32 TransferSize=0; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + EmmcDMABufferBase = PcdGet32(PcdEmmcDMABufferBase); + EmmcDMABufferBase += PHY_CH2_OFFSET; + //Check controller status to make sure there is no error. + + while (Count) + { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO) + { + //TransferSize = MmioRead32 (SdMmcBaseAddr + MSHCI_TBBCNT); + CopyMem((VOID *)Buffer, (VOID *)(EmmcDMABufferBase+PHY_BUF_OFFSET), BlockCount*BLEN_512BYTES); + DEBUG ((EFI_D_INFO, "MSHC_ReadDMA Over %d Blocks\n", BlockCount)); + break; + } + else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & (DATA_ERR|DATA_TOUT)) + { + DEBUG ((EFI_D_ERROR, "MSHC_ReadDMA Err RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS))); + } + + else + { + Count--; + MicroSecondDelay(1); + DEBUG ((EFI_D_INFO, ".\n")); + } + + } + + if(Count!=0) + { + Status = EFI_SUCCESS; + } + else + { + DEBUG ((EFI_D_ERROR, "MSHC_ReadDMA bad buffer size RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS))); + Status = EFI_BAD_BUFFER_SIZE; + MmioWrite32 ((SdMmcBaseAddr + MSHCI_PLDMND), 7); + + } + return Status; +} + +EFI_STATUS MSHC_WriteDMA(IN VOID *Buffer, IN UINTN BlockCount) +{ + EFI_STATUS Status; + UINT32 SdMmcBaseAddr; + UINTN Count=MAX_RETRY_COUNT; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcBase); + //Check controller status to make sure there is no error. + + while (Count) + { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO) + { + DEBUG ((EFI_D_INFO, "MSHC_writeDMA Over %d blocks\n", BlockCount)); + break; + } + else + { + MicroSecondDelay(1); + Count--; + } + + } + + if(Count!=0) + { + Status = EFI_SUCCESS; + } + else + { + Status = EFI_BAD_BUFFER_SIZE; + MmioWrite32 ((SdMmcBaseAddr + MSHCI_PLDMND), 7); + DEBUG ((EFI_D_ERROR, "MSHC_writeDMA bad buffer size RINT:0x%x \n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS))); + } + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_5250.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_5250.h new file mode 100755 index 000000000..7dbf590e1 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_5250.h @@ -0,0 +1,323 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _MSHCDXE_5250_H_ +#define _MSHCDXE_5250_H_ + + +/* + * Controller registers + */ +/*****************************************************/ +/* MSHC Internal Registers */ +/*****************************************************/ + +#define MSHCI_CTRL 0x00 /* Control */ +#define MSHCI_PWREN 0x04 /* Power-enable */ +#define MSHCI_CLKDIV 0x08 /* Clock divider */ +#define MSHCI_CLKSRC 0x0C /* Clock source */ +#define MSHCI_CLKENA 0x10 /* Clock enable */ +#define MSHCI_TMOUT 0x14 /* Timeout */ +#define MSHCI_CTYPE 0x18 /* Card type */ +#define MSHCI_BLKSIZ 0x1C /* Block Size */ +#define MSHCI_BYTCNT 0x20 /* Byte count */ +#define MSHCI_INTMSK 0x24 /* Interrupt Mask */ +#define MSHCI_CMDARG 0x28 /* Command Argument */ +#define MSHCI_CMD 0x2C /* Command */ +#define MSHCI_RESP0 0x30 /* Response 0 */ +#define MSHCI_RESP1 0x34 /* Response 1 */ +#define MSHCI_RESP2 0x38 /* Response 2 */ +#define MSHCI_RESP3 0x3C /* Response 3 */ +#define MSHCI_MINTSTS 0x40 /* Masked interrupt status */ +#define MSHCI_RINTSTS 0x44 /* Raw interrupt status */ +#define MSHCI_STATUS 0x48 /* Status */ +#define MSHCI_FIFOTH 0x4C /* FIFO threshold */ +#define MSHCI_CDETECT 0x50 /* Card detect */ +#define MSHCI_WRTPRT 0x54 /* Write protect */ +#define MSHCI_GPIO 0x58 /* General Purpose IO */ +#define MSHCI_TCBCNT 0x5C /* Transferred CIU byte count */ +#define MSHCI_TBBCNT 0x60 /* Transferred host/DMA to/from byte count */ +#define MSHCI_DEBNCE 0x64 /* Card detect debounce */ +#define MSHCI_USRID 0x68 /* User ID */ +#define MSHCI_VERID 0x6C /* Version ID */ +#define MSHCI_HCON 0x70 /* Hardware Configuration */ +#define MSHCI_UHS_REG 0x74 /* UHS and DDR setting */ +#define MSHCI_BMOD 0x80 /* Bus mode register */ +#define MSHCI_PLDMND 0x84 /* Poll demand */ +#define MSHCI_DBADDR 0x88 /* Descriptor list base address */ +#define MSHCI_IDSTS 0x8C /* Internal DMAC status */ +#define MSHCI_IDINTEN 0x90 /* Internal DMAC interrupt enable */ +#define MSHCI_DSCADDR 0x94 /* Current host descriptor address */ +#define MSHCI_BUFADDR 0x98 /* Current host buffer address */ +#define MSHCI_CLKSEL 0x9C /* Drv/sample clock selection register */ +#define MSHCI_WAKEUPCON 0xA0 /* Wakeup control register */ +#define MSHCI_CLOCKCON 0xA4 /* Clock (delay) control register */ +#define MSHCI_FIFO 0x200 +#define MSHCI_FIFODAT(x) (x) /* FIFO data read write */ + + +/***************************************************** + * Control Register Register + * MSHCI_CTRL - offset 0x00 + *****************************************************/ + +#define CTRL_RESET (0x1<<0) /* Reset DWC_mobile_storage controller */ +#define FIFO_RESET (0x1<<1) /* Reset FIFO */ +#define DMA_RESET (0x1<<2) /* Reset DMA interface */ +#define INT_ENABLE (0x1<<4) /* Global interrupt enable/disable bit */ +#define DMA_ENABLE (0x1<<5) /* DMA transfer mode enable/disable bit */ +#define READ_WAIT (0x1<<6) /* For sending read-wait to SDIO cards */ +#define SEND_IRQ_RESP (0x1<<7) /* Send auto IRQ response */ +#define ABRT_READ_DATA (0x1<<8) +#define SEND_CCSD (0x1<<9) +#define SEND_AS_CCSD (0x1<<10) +#define CEATA_INTSTAT (0x1<<11) +#define CARD_VOLA (0xF<<16) +#define CARD_VOLB (0xF<<20) +#define ENABLE_OD_PULLUP (0x1<<24) +#define ENABLE_IDMAC (0x1<<25) +#define MSHCI_RESET_ALL (0x1) + +/***************************************************** + * Power Enable Register + * MSHCI_PWREN - offset 0x04 + *****************************************************/ +#define POWER_ENABLE (0x1<<0) + +/***************************************************** +* Clock Enable Register +* MSHCI_CLKENA - offset 0x10 +*****************************************************/ +#define CLK_SDMMC_MAX (48000000) /* 96Mhz. it SHOULDBE optimized */ +#define CLK_ENABLE (0x1<<0) +#define CLK_DISABLE (0x0<<0) + + +/***************************************************** + * Interrupt Mask Register + * MSHCI_INTMSK - offset 0x24 + *****************************************************/ +#define INT_MASK (0xFFFF<<0) +#define SDIO_INT_MASK (0xFFFF<<16) +#define SDIO_INT_ENABLE (0x1<<16) + +/* interrupt bits */ +#define INTMSK_ALL 0xFFFFFFFF +#define INTMSK_CDETECT (0x1<<0) +#define INTMSK_RE (0x1<<1) +#define INTMSK_CDONE (0x1<<2) +#define INTMSK_DTO (0x1<<3) +#define INTMSK_TXDR (0x1<<4) +#define INTMSK_RXDR (0x1<<5) +#define INTMSK_RCRC (0x1<<6) +#define INTMSK_DCRC (0x1<<7) +#define INTMSK_RTO (0x1<<8) +#define INTMSK_DRTO (0x1<<9) +#define INTMSK_HTO (0x1<<10) +#define INTMSK_FRUN (0x1<<11) +#define INTMSK_HLE (0x1<<12) +#define INTMSK_SBE (0x1<<13) +#define INTMSK_ACD (0x1<<14) +#define INTMSK_EBE (0x1<<15) +#define INTMSK_DMA (INTMSK_ACD|INTMSK_RXDR|INTMSK_TXDR) + +#define INT_SRC_IDMAC (0x0) +#define INT_SRC_MINT (0x1) + + +/***************************************************** + * Command Register + * MSHCI_CMD - offset 0x2C + *****************************************************/ + +#define CMD_RESP_EXP_BIT (0x1<<6) +#define CMD_RESP_LENGTH_BIT (0x1<<7) +#define CMD_CHECK_CRC_BIT (0x1<<8) +#define CMD_DATA_EXP_BIT (0x1<<9) +#define CMD_RW_BIT (0x1<<10) +#define CMD_TRANSMODE_BIT (0x1<<11) +#define CMD_SENT_AUTO_STOP_BIT (0x1<<12) +#define CMD_WAIT_PRV_DAT_BIT (0x1<<13) +#define CMD_ABRT_CMD_BIT (0x1<<14) +#define CMD_SEND_INIT_BIT (0x1<<15) +#define CMD_CARD_NUM_BITS (0x1F<<16) +#define CMD_SEND_CLK_ONLY (0x1<<21) +#define CMD_READ_CEATA (0x1<<22) +#define CMD_CCS_EXPECTED (0x1<<23) +#define CMD_USE_HOLD_REG (0x1<<29) +#define CMD_STRT_BIT (0x1<<31) +#define CMD_ONLY_CLK (CMD_STRT_BIT | CMD_SEND_CLK_ONLY | \ + CMD_WAIT_PRV_DAT_BIT) + +/***************************************************** + * Raw Interrupt Register + * MSHCI_RINTSTS - offset 0x44 + *****************************************************/ +#define INT_STATUS (0xFFFF<<0) +#define SDIO_INTR (0xFFFF<<16) +#define DATA_ERR (INTMSK_EBE|INTMSK_SBE|INTMSK_HLE|INTMSK_FRUN |\ + INTMSK_EBE |INTMSK_DCRC) +#define DATA_TOUT (INTMSK_HTO|INTMSK_DRTO) +#define DATA_STATUS (DATA_ERR|DATA_TOUT|INTMSK_RXDR|INTMSK_TXDR|INTMSK_DTO) +#define CMD_STATUS (INTMSK_RTO|INTMSK_RCRC|INTMSK_CDONE|INTMSK_RE) +#define CMD_ERROR (INTMSK_RCRC|INTMSK_RTO|INTMSK_RE) + + +/***************************************************** + * Status Register + * MSHCI_STATUS - offset 0x48 + *****************************************************/ +#define FIFO_RXWTRMARK (0x1<<0) +#define FIFO_TXWTRMARK (0x1<<1) +#define FIFO_EMPTY (0x1<<2) +#define FIFO_FULL (0x1<<3) +#define CMD_FSMSTAT (0xF<<4) +#define DATA_3STATUS (0x1<<8) +#define DATA_BUSY (0x1<<9) +#define DATA_MCBUSY (0x1<<10) +#define RSP_INDEX (0x3F<<11) +#define FIFO_COUNT (0x1FFF<<17) +#define DMA_ACK (0x1<<30) +#define DMA_REQ (0x1<<31) +#define FIFO_WIDTH (0x4) +#define FIFO_DEPTH (0x20) +#define FIFO_SIZE (0x80) +#define GET_FIFO_COUNT(x) (((x)&0x3ffe0000)>>17) + + + +/***************************************************** + * FIFO Threshold Watermark Register + * MSHCI_FIFOTH - offset 0x4C + *****************************************************/ +#define TX_WMARK (0xFFF<<0) +#define RX_WMARK (0xFFF<<16) +#define MSIZE_MASK (0x7<<28) + +/* DW DMA Mutiple Transaction Size */ +#define MSIZE_1 (0<<28) +#define MSIZE_4 (1<<28) +#define MSIZE_8 (2<<28) +#define MSIZE_16 (3<<28) +#define MSIZE_32 (4<<28) +#define MSIZE_64 (5<<28) +#define MSIZE_128 (6<<28) +#define MSIZE_256 (7<<28) + +#define TX_WMARK_DEFAULT (0x10<<0) +#define RX_WMARK_DEFAULT (0x10<<16) + +//#define TX_WMARK_DEFAULT (0x40<<0) +//#define RX_WMARK_DEFAULT (0x3F<<16) + + +/***************************************************** + * Bus Mode Register + * MSHCI_UHS_REG - offset 0x74 + *****************************************************/ +#define UHS_DDR (0x1<<16) +#define UHS_NON_DDR (0x0<<16) +#define BUSMODE_DDR 1 +#define BUSMODE_NON_DDR 0 + +/***************************************************** + * Bus Mode Register + * MSHCI_BMOD - offset 0x80 + *****************************************************/ +#define BMOD_IDMAC_RESET (0x1<<0) +#define BMOD_IDMAC_FB (0x1<<1) +#define BMOD_IDMAC_ENABLE (0x1<<7) + +/***************************************************** + * Hardware Configuration Register + * MSHCI_IDSTS - offset 0x8c + *****************************************************/ +#define IDSTS_FSM (0xf<<13) +#define IDSTS_EB (0x7<<10) +#define IDSTS_AIS (0x1<<9) +#define IDSTS_NIS (0x1<<8) +#define IDSTS_CES (0x1<<5) +#define IDSTS_DU (0x1<<4) +#define IDSTS_FBE (0x1<<2) +#define IDSTS_RI (0x1<<1) +#define IDSTS_TI (0x1<<0) + + +/***************************************************** + * Card Type Register + * MSHCI_CTYPE - offset 0x18 + *****************************************************/ +#define CARD_WIDTH14 (0xFFFF<<0) +#define CARD_WIDTH8 (0xFFFF<<16) + +struct mshci_idmac { + UINT32 des0; + UINT32 des1; + UINT32 des2; + UINT32 des3; +#define MSHCI_IDMAC_OWN (1<<31) +#define MSHCI_IDMAC_ER (1<<5) +#define MSHCI_IDMAC_CH (1<<4) +#define MSHCI_IDMAC_FS (1<<3) +#define MSHCI_IDMAC_LD (1<<2) +#define MSHCI_IDMAC_DIC (1<<1) +#define INTMSK_IDMAC_ALL (0x337) +#define INTMSK_IDMAC_ERROR (0x214) +}; + +typedef enum { + READ, + WRITE +} OPERATION_TYPE; + + +/***************************************************** + * DMA Buffer structure + * + * CH0 for eMMC 0x40300000--0x40380000 + * CH2 for SD Card 0x40380000--0x40400000 + *****************************************************/ +#define EMMC_DMA_PHYSICAL_BUFFER_BASE 0x40300000 +#define EMMC_DMA_PHYSICAL_BUFFER_SIZE 0x00100000 //1MB +#define PHY_CH2_OFFSET 0x80000 +#define PHY_BUF_OFFSET 0x1000 //4K +#define PHY_BUF_SIZE 0x1000 //4K + +//#define MAX_MSHC_TRANSFER_SIZE 0x4000 //16K +#define MAX_MSHC_TRANSFER_SIZE 0x40000 //512blocks, 256KB + + + + +/***************************************************** + * External Functions + *****************************************************/ + + +EFI_STATUS InitializeMSHC (VOID); +VOID UpdateMSHCClkFrequency (UINTN NewCLK); +void MSHC_reset_fifo(void); +extern void MSHC_reset_all(void); +extern VOID PrepareTransfer (IN OUT VOID *Buffer, UINTN ByteCount, IN OPERATION_TYPE OperationType); +extern EFI_STATUS MSHC_ReadFIFO(IN UINTN Size32, OUT VOID *Buffer); +extern EFI_STATUS MSHC_WriteFIFO(IN UINTN Size32, IN VOID *Buffer); +void mshci_set_mdma_desc(UINT8 *desc_vir, UINT8 *desc_phy, + UINT32 des0, UINT32 des1, UINT32 des2); +EFI_STATUS MSHC_ReadDMA(OUT VOID *Buffer, IN UINTN BlockCount); +EFI_STATUS MSHC_WriteDMA(IN VOID *Buffer, IN UINTN BlockCount); + + + +#endif + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_CMD.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_CMD.h new file mode 100755 index 000000000..cbaa7b935 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/SDHCDxe_EVT1/SDHCDxe_CMD.h @@ -0,0 +1,165 @@ +/** @file + + Copyright (c) 2011, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _MSHCDXE_CMD_H_ +#define _MSHCDXE_CMD_H_ + + + +#define HosttoCard 0x1 +#define CardtoHost 0x0 + +#define ENDMA BIT0 +#define ENBLKCNT BIT1 +#define RD1WT0 BIT4 +#define MUL1SIN0 BIT5 +#define RSPTYP136 (0x1 << 16) +#define RSPTYP48 (0x2 << 16) +#define RSPTYP48B (0x3 << 16) +#define ENCMDCRC BIT19 +#define ENCMDIDX BIT20 +#define DATAPRNT BIT21 + + +#define CMDCOMP BIT0 +#define TRNSCOMP BIT1 +#define RDYFORWT BIT4 +#define RDYFORRD BIT5 +#define CARDINSERT BIT6 +#define CARDREMOVE BIT7 +#define ERRINT BIT15 +#define CMDTOUTERR BIT16 +#define CMDCRCERR BIT17 +#define CMDEBITERR BIT18 +#define CMDIDXERR BIT19 +#define DATATOUTERR BIT20 +#define DATACRCERR BIT21 +#define DATAEBITERR BIT22 + +#define HCS BIT30 //Host capacity support/1 = Supporting high capacity + + + +/* Command Definitions */ +#define INDX(CMD_INDX) (CMD_INDX & 0x3F) + +#define CMD0 INDX(0) +#define CMD0_INT_EN (CMDCOMP | CMDEBITERR) + +#define CMD1 (INDX(1) | RSPTYP48) +#define CMD1_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD2 (INDX(2) | ENCMDCRC | RSPTYP136) +#define CMD2_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD3 (INDX(3) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD3_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD5 (INDX(5) | RSPTYP48) +#define CMD5_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD7 (INDX(7) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD7_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +//#define CMD8 (INDX(8) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD8 (INDX(8) | ENCMDIDX | RSPTYP48) +#define CMD8_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) +//Reserved(0)[12:31], Supply voltage(1)[11:8], check pattern(0xCE)[7:0] = 0x1CE +//#define CMD8_ARG (0x0UL << 12 | BIT8 | 0xCEUL << 0) +#define CMD8_ARG (0x0UL << 12 | BIT8 | 0xAAUL << 0) + +#define CMD9 (INDX(9) | ENCMDCRC | RSPTYP136) +#define CMD9_INT_EN (CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD13 (INDX(13) | RSPTYP48) +#define CMD13_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR) + + +//#define CMD16 (INDX(16) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD16 (INDX(16) | ENCMDIDX | RSPTYP48) +#define CMD16_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD17 (INDX(17) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | RD1WT0) +#define CMD17_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORRD | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR) + +//#define CMD18 (INDX(18) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | MUL1SIN0 | RD1WT0 | ENBLKCNT | ENDMA) +#define CMD18 (INDX(18) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 ) +#define CMD18_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORRD | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR) + +#define CMD23 (INDX(23) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD23_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD24 (INDX(24) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD24_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORWT | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR) + +//#define CMD25 (INDX(25) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | MUL1SIN0 | ENBLKCNT | ENDMA) +#define CMD25 (INDX(25) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD25_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORWT | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR) + +//#define CMD55 (INDX(55) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD55 (INDX(55) | ENCMDIDX | RSPTYP48) +#define CMD55_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define ACMD41 (INDX(41) | RSPTYP48) +#define ACMD41_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define ACMD6 (INDX(6) | RSPTYP48) +#define ACMD6_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD62 (INDX(62) | RSPTYP48) +#define CMD62_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + + + +/* +EFI_STATUS +EFI_SUCCESS 0 + +EFI_LOAD_ERROR 1 +EFI_INVALID_PARAMETER 2 +EFI_UNSUPPORTED 3 +EFI_BAD_BUFFER_SIZE 4 +EFI_BUFFER_TOO_SMALL 5 +EFI_NOT_READY 6 +EFI_DEVICE_ERROR 7 +EFI_WRITE_PROTECTED 8 +EFI_OUT_OF_RESOURCES 9 +EFI_VOLUME_CORRUPTED 10 +EFI_VOLUME_FULL 11 +EFI_NO_MEDIA 12 +EFI_MEDIA_CHANGED 13 +EFI_NOT_FOUND 14 +EFI_ACCESS_DENIED 15 +EFI_NO_RESPONSE 16 +EFI_NO_MAPPING 17 +EFI_TIMEOUT 18 +EFI_NOT_STARTED 19 +EFI_ALREADY_STARTED 20 +EFI_ABORTED 21 +EFI_ICMO_ERROR 22 +EFI_TFTP_ERROR 23 +EFI_PROTOCOL_ERROR 24 +EFI_INCOMPATIBLE_VERSION 25 +EFI_SECURITY_VIOLATION 26 +EFI_CRC_ERROR 27 +EFI_END_OF_MEDIA 28 +EFI_END_OF_FILE 31 +EFI_INVALID_LANGUAGE 32 +EFI_COMPROMISED_DATA 33 + + +*/ + +#endif + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/TimerDxe/TimerDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/TimerDxe/TimerDxe.c new file mode 100644 index 000000000..4eab280e6 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/TimerDxe/TimerDxe.c @@ -0,0 +1,469 @@ +/** @file + Template for Timer Architecture Protocol driver of the ARM flavor + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> + +#include <Protocol/Timer.h> +#include <Protocol/HardwareInterrupt.h> + +#include <Library/ExynosTimerLib.h> +#include <Platform/ArmPlatform.h> + +// The notification function to call on every timer interrupt. +volatile EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL; +EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL; + +// The current period of the timer interrupt +volatile UINT64 mTimerPeriod = 0; + +// Cached copy of the Hardware Interrupt protocol instance +EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL; + +// Cached interrupt vector +UINTN gVector; + +UINT32 mLastTickCount; + +/** + + C Interrupt Handler called in the interrupt context when Source interrupt is active. + + + @param Source Source of the interrupt. Hardware routing off a specific platform defines + what source means. + + @param SystemContext Pointer to system register context. Mostly used by debuggers and will + update the system context after the return from the interrupt if + modified. Don't change these values unless you know what you are doing + +**/ +VOID +EFIAPI +TimerInterruptHandler ( + IN HARDWARE_INTERRUPT_SOURCE Source, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EFI_TPL OriginalTPL; + UINT32 Tmp; + UINT32 PWMTimerBase; + + + PWMTimerBase=PcdGet32(PcdPWMTimerBase); + //DEBUG ((EFI_D_ERROR, "PWM Timer INT Occur\n")); + // + // DXE core uses this callback for the EFI timer tick. The DXE core uses locks + // that raise to TPL_HIGH and then restore back to current level. Thus we need + // to make sure TPL level is set to TPL_HIGH while we are handling the timer tick. + // + OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + // clear the periodic interrupt + Tmp = MmioRead32 (PWMTimerBase + PWM_TINT_CSTAT_OFFSET); + MmioWrite32 ((PWMTimerBase + PWM_TINT_CSTAT_OFFSET), Tmp); + + // signal end of interrupt early to help avoid losing subsequent ticks from long duration handlers + gInterrupt->EndOfInterrupt (gInterrupt, Source); + + if (mTimerNotifyFunction) { + mTimerNotifyFunction (mTimerPeriod); + } + + gBS->RestoreTPL (OriginalTPL); +} + +/** + This function registers the handler NotifyFunction so it is called every time + the timer interrupt fires. It also passes the amount of time since the last + handler call to the NotifyFunction. If NotifyFunction is NULL, then the + handler is unregistered. If the handler is registered, then EFI_SUCCESS is + returned. If the CPU does not support registering a timer interrupt handler, + then EFI_UNSUPPORTED is returned. If an attempt is made to register a handler + when a handler is already registered, then EFI_ALREADY_STARTED is returned. + If an attempt is made to unregister a handler when a handler is not registered, + then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to + register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR + is returned. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param NotifyFunction The function to call when a timer interrupt fires. This + function executes at TPL_HIGH_LEVEL. The DXE Core will + register a handler for the timer interrupt, so it can know + how much time has passed. This information is used to + signal timer based events. NULL will unregister the handler. + @retval EFI_SUCCESS The timer handler was registered. + @retval EFI_UNSUPPORTED The platform does not support timer interrupts. + @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already + registered. + @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not + previously registered. + @retval EFI_DEVICE_ERROR The timer handler could not be registered. + +**/ +EFI_STATUS +EFIAPI +TimerDriverRegisterHandler ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN EFI_TIMER_NOTIFY NotifyFunction + ) +{ + if ((NotifyFunction == NULL) && (mTimerNotifyFunction == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((NotifyFunction != NULL) && (mTimerNotifyFunction != NULL)) { + return EFI_ALREADY_STARTED; + } + + DEBUG ((EFI_D_ERROR, "++TimerDriverRegisterHandler\n")); + mTimerNotifyFunction = NotifyFunction; + + return EFI_SUCCESS; +} + +/** + Make sure all ArrmVe Timers are disabled +**/ +VOID +EFIAPI +ExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT32 PWMTimerBase; + + PWMTimerBase=PcdGet32(PcdPWMTimerBase); + // All PWM timer is off + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), 0); +} + +/** + + This function adjusts the period of timer interrupts to the value specified + by TimerPeriod. If the timer period is updated, then the selected timer + period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. + If an error occurs while attempting to update the timer period, then the + timer hardware will be put back in its state prior to this call, and + EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt + is disabled. This is not the same as disabling the CPU's interrupts. + Instead, it must either turn off the timer hardware, or it must adjust the + interrupt controller so that a CPU interrupt is not generated when the timer + interrupt fires. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod The rate to program the timer interrupt in 100 nS units. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is + returned. If the timer is programmable, then the timer period + will be rounded up to the nearest timer period that is supported + by the timer hardware. If TimerPeriod is set to 0, then the + timer interrupts will be disabled. + + + @retval EFI_SUCCESS The timer period was changed. + @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt. + @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error. + +**/ +EFI_STATUS +EFIAPI +TimerDriverSetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ) +{ + EFI_STATUS Status; + UINT64 TimerTicks; + UINT32 Tmp; + UINT32 PWMTimerBase; + + PWMTimerBase=PcdGet32(PcdPWMTimerBase); + // Stop PWM timer 0 + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + Tmp &= ~(0x1F << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET) ,Tmp); + + if (TimerPeriod == 0) { + // leave timer disabled from above, and... + Tmp = MmioRead32 (PWMTimerBase + PWM_TINT_CSTAT_OFFSET); + Tmp &= ~(1 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TINT_CSTAT_OFFSET), Tmp); + // disable timer 0/1 interrupt for a TimerPeriod of 0 + Status = gInterrupt->DisableInterruptSource (gInterrupt, gVector); + } else { + // Convert TimerPeriod into 1MHz clock counts (us units = 100ns units / 10) + TimerTicks = DivU64x32 (TimerPeriod, 10); + // if it's larger than 32-bits, pin to highest value + if (TimerTicks > 0xffffffff) { + TimerTicks = 0xffffffff; + } + + // PWM Timer 0 used by Period counter with Auto re-load mode + MmioWrite32 ((PWMTimerBase + PWM_TCNTB0_OFFSET), TimerTicks); + // Set and Clear PWM Manually update for Timer 0 + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + Tmp |= (0x2 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + Tmp &= ~(0x2 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + // Set Auto re-load and start Timer + Tmp |= (0x9 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + // enable PWM Timer 0 interrupts + Tmp = MmioRead32 (PWMTimerBase + PWM_TINT_CSTAT_OFFSET); + Tmp |= (1 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TINT_CSTAT_OFFSET), Tmp); + + Status = gInterrupt->EnableInterruptSource (gInterrupt, gVector); + } + + // Save the new timer period + mTimerPeriod = TimerPeriod; + return Status; +} + +/** + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is + returned, then the timer is currently disabled. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. If + 0 is returned, then the timer is currently disabled. + + + @retval EFI_SUCCESS The timer period was returned in TimerPeriod. + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ) +{ + if (TimerPeriod == NULL) { + return EFI_INVALID_PARAMETER; + } + + *TimerPeriod = mTimerPeriod; + return EFI_SUCCESS; +} + +/** + This function generates a soft timer interrupt. If the platform does not support soft + timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned. + If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler() + service, then a soft timer interrupt will be generated. If the timer interrupt is + enabled when this service is called, then the registered handler will be invoked. The + registered handler should not be able to distinguish a hardware-generated timer + interrupt from a software-generated timer interrupt. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS The soft timer interrupt was generated. + @retval EFI_UNSUPPORTED The platform does not support the generation of soft timer interrupts. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGenerateSoftInterrupt ( + IN EFI_TIMER_ARCH_PROTOCOL *This + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Interface structure for the Timer Architectural Protocol. + + @par Protocol Description: + This protocol provides the services to initialize a periodic timer + interrupt, and to register a handler that is called each time the timer + interrupt fires. It may also provide a service to adjust the rate of the + periodic timer interrupt. When a timer interrupt occurs, the handler is + passed the amount of time that has passed since the previous timer + interrupt. + + @param RegisterHandler + Registers a handler that will be called each time the + timer interrupt fires. TimerPeriod defines the minimum + time between timer interrupts, so TimerPeriod will also + be the minimum time between calls to the registered + handler. + + @param SetTimerPeriod + Sets the period of the timer interrupt in 100 nS units. + This function is optional, and may return EFI_UNSUPPORTED. + If this function is supported, then the timer period will + be rounded up to the nearest supported timer period. + + + @param GetTimerPeriod + Retrieves the period of the timer interrupt in 100 nS units. + + @param GenerateSoftInterrupt + Generates a soft timer interrupt that simulates the firing of + the timer interrupt. This service can be used to invoke the registered handler if the timer interrupt has been masked for + a period of time. + +**/ +EFI_TIMER_ARCH_PROTOCOL gTimer = { + TimerDriverRegisterHandler, + TimerDriverSetTimerPeriod, + TimerDriverGetTimerPeriod, + TimerDriverGenerateSoftInterrupt +}; + + +/** + Initialize the state information for the Timer Architectural Protocol and + the Timer Debug support protocol that allows the debugger to break into a + running program. + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +TimerInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HANDLE Handle = NULL; + EFI_STATUS Status; + + UINT32 Tmp; + UINT32 PWMTimerBase; + + PWMTimerBase=PcdGet32(PcdPWMTimerBase); + // Find the interrupt controller protocol. ASSERT if not found. + Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt); + ASSERT_EFI_ERROR (Status); + + // Timer Source : SCLK_MPLL(800Mhz) + Tmp = MmioRead32(0x10020250); + Tmp &= ~(0xF << 24); + Tmp |= (0x6 << 24); + MmioWrite32(0x10020250, Tmp); + // Timer 0,1,2 prescale:0x02(/(0x02+1)) => 266666666hz (at least 0x01+1) + Tmp = MmioRead32(PWMTimerBase + PWM_TCFG0_OFFSET); + Tmp &= ~((0xFF << 8) + (0xFF << 0)); + Tmp |= (0x02 << 8) + (0x02 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCFG0_OFFSET), Tmp); + // Timer 0,1,2 divider:0x2(/4) => 66666666hz + MmioWrite32 ((PWMTimerBase + PWM_TCFG1_OFFSET), (0x2 << 2) + (0x2 << 1) + (0x2 << 0)); +/* + // PWM Input source clock is 100Mhz and Configure 1Mhz for PWM Timer + Tmp = MmioRead32 (PWMTimerBase + PWM_TCFG0_OFFSET); + Tmp &= ~(0xFF << 0); + Tmp |= (0x63 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCFG0_OFFSET), Tmp); + MmioWrite32 ((PWMTimerBase + PWM_TCFG1_OFFSET), 0x0); +*/ + //Timer 1 INT disable + Tmp = MmioRead32 (PWMTimerBase + PWM_TINT_CSTAT_OFFSET); + Tmp &= ~(1 << 1); + MmioWrite32 ((PWMTimerBase + PWM_TINT_CSTAT_OFFSET), Tmp); + + // configure timer 1 Stop + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + Tmp &= ~(0xF << 8); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + // PWM Timer 1 used by Free running counter with Auto re-load mode + MmioWrite32 ((PWMTimerBase + PWM_TCNTB1_OFFSET), 0xFFFFFFFF); + // Set and Clear PWM Manually update for Timer 1 + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + Tmp |= (0x2 << 8); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + Tmp &= ~(0x2 << 8); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + // Set Auto re-load and start Timer + Tmp |= (0x9 << 8); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + // Install interrupt handler + gVector = PWM_TIMER0_INTERRUPT_NUM; + Status = gInterrupt->RegisterInterruptSource (gInterrupt, gVector, TimerInterruptHandler); + ASSERT_EFI_ERROR (Status); + + // Disable the timer + Status = TimerDriverSetTimerPeriod (&gTimer, 0); + ASSERT_EFI_ERROR (Status); + + // PWM Timer 0 make to stop + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + Tmp &= ~(0x1F << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + // PWM Timer 0 INT disable + Tmp = MmioRead32 (PWMTimerBase + PWM_TINT_CSTAT_OFFSET); + Tmp &= ~(1 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TINT_CSTAT_OFFSET), Tmp); + + // PWM Timer 0 used by Period counter with Auto re-load mode + MmioWrite32 ((PWMTimerBase + PWM_TCNTB0_OFFSET), FixedPcdGet32(PcdTimerPeriod)); + Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); + ASSERT_EFI_ERROR (Status); + + // Set and Clear PWM Manually update for Timer 0 + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + Tmp |= (0x2 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + Tmp &= ~(0x2 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + // Set Auto re-load and start Timer + Tmp |= (0x9 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + //PWM Timer0 INT enable + Tmp = MmioRead32 (PWMTimerBase + PWM_TINT_CSTAT_OFFSET); + Tmp |= (1 << 0); + MmioWrite32 ((PWMTimerBase + PWM_TINT_CSTAT_OFFSET), Tmp); + + // Install the Timer Architectural Protocol onto a new handle + Status = gBS->InstallMultipleProtocolInterfaces( + &Handle, + &gEfiTimerArchProtocolGuid, &gTimer, + NULL + ); + ASSERT_EFI_ERROR(Status); + + // Register for an ExitBootServicesEvent + Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/TimerDxe/TimerDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/TimerDxe/TimerDxe.inf new file mode 100644 index 000000000..019d84477 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/TimerDxe/TimerDxe.inf @@ -0,0 +1,54 @@ +#/** @file +# +# Component discription file for Timer module +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TimerDxe + FILE_GUID = 494ffd22-3228-4b7e-ad40-7e780fa88301 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = TimerInitialize + +[Sources.common] + TimerDxe.c + +[Packages] + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + + +[LibraryClasses] + BaseLib + IoLib + UefiBootServicesTableLib + UefiDriverEntryPoint + TimerLib + +[Guids] + +[Protocols] + gEfiTimerArchProtocolGuid + gHardwareInterruptProtocolGuid + + +[Pcd.common] + gEmbeddedTokenSpaceGuid.PcdTimerPeriod + gExynosPkgTokenSpaceGuid.PcdPWMTimerBase +[Depex] + gHardwareInterruptProtocolGuid diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.c new file mode 100755 index 000000000..87f937924 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.c @@ -0,0 +1,1378 @@ +/** @file + MMC/SD Card driver for Secure Digital Host Controller + + This driver always produces a BlockIo protocol but it starts off with no Media + present. A TimerCallBack detects when media is inserted or removed and after + a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the + media to be detected (or removed) and the BlockIo Media structure will get + updated. No MMC/SD Card harward registers are updated until the first BlockIo + ReadBlocks/WriteBlocks after media has been insterted (booting with a card + plugged in counts as an insertion event). + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include <Library/TimerLib.h> +#include <Library/PcdLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Protocol/ExynosGpio.h> +#include <Platform/ArmPlatform.h> +#include <Platform/Exynos5250.h> +#include <Platform/Arndale5250.h> + +#include "eMMCDxe.h" + + + +#define DateInformation "20120723_007" + + +MSHC_OPERATION_MODE MSHC_operation_mode=MSHC_FIFO; +//MSHC_OPERATION_MODE MSHC_operation_mode=MSHC_IDMA; + + +//#undef EFI_D_INFO +//#define EFI_D_INFO 1 + + + +CARD_INFO gCardInfo; +BOOLEAN gMediaChange = TRUE; +BOOLEAN gCardInit = FALSE; + + +EFI_BLOCK_IO_MEDIA gSDMMCMedia = { + SIGNATURE_32('e','m','m','c'), // MediaId + FALSE, // RemovableMedia + TRUE, // MediaPresent + FALSE, // LogicalPartition + FALSE, // ReadOnly + FALSE, // WriteCaching + 512, // BlockSize + 4, // IoAlign + 0, // Pad + 0 // LastBlock +}; + +typedef struct { + VENDOR_DEVICE_PATH Mmc; + EFI_DEVICE_PATH End; +} MSHC_DEVICE_PATH; + +MSHC_DEVICE_PATH gMSHCDevicePath = { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + (UINT8)(sizeof(VENDOR_DEVICE_PATH)), + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8), + 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } +}; + + + +// +// Internal Functions +// + + + + +VOID +ParseCardCIDData ( + UINT32 Response0, + UINT32 Response1, + UINT32 Response2, + UINT32 Response3 + ) +{ + gCardInfo.CIDData.MDT = ((Response0 >> 8) & 0xFFF); + gCardInfo.CIDData.PSN = (((Response0 >> 24) & 0xFF) | ((Response1 & 0xFFFFFF) << 8)); + gCardInfo.CIDData.PRV = ((Response1 >> 24) & 0xFF); + gCardInfo.CIDData.PNM[4] = ((Response2) & 0xFF); + gCardInfo.CIDData.PNM[3] = ((Response2 >> 8) & 0xFF); + gCardInfo.CIDData.PNM[2] = ((Response2 >> 16) & 0xFF); + gCardInfo.CIDData.PNM[1] = ((Response2 >> 24) & 0xFF); + gCardInfo.CIDData.PNM[0] = ((Response3) & 0xFF); + gCardInfo.CIDData.OID = ((Response3 >> 8) & 0xFFFF); + gCardInfo.CIDData.MID = ((Response3 >> 24) & 0xFF); +} + + +EFI_STATUS +MSHC_SendCmd ( + UINTN Cmd, + UINTN CmdInterruptEnableVal, + UINTN CmdArgument + ) +{ + UINTN MmcStatus = 0; + volatile UINTN RetryCount = 0; + int cmd_flags = 0; + int timeout=0; + UINT32 SdMmcBaseAddr; + //UINT32 MSHCRintStatus=0; + + DEBUG ((EFI_D_INFO, "CMD = %d\n", (Cmd&0x3F))); + + timeout = MAX_RETRY_COUNT; + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + //1. Check if Data busy or not + while(MmioRead32(SdMmcBaseAddr + MSHCI_STATUS) & (DATA_BUSY)) + { + if (timeout == 0) + { + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd timeout : CMD = %d\n", Cmd)); + return EFI_DEVICE_ERROR; + } + timeout--; + MicroSecondDelay(1); + } + + // 2. Check if Raw interrupt is command done + /*MSHCRintStatus = MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS); + if ((MSHCRintStatus & (INTMSK_CDONE|INTMSK_ACD)) == 0) + { + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd interrupt error : INT = %x\n", MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS))); + } */ + + // 3. Clear Raw interrupt + MmioWrite32 ((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_ALL); + + // 4. prepare data + //mshci_reset_fifo(); + + //5. Set command argument register + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMDARG), CmdArgument); + + // 6. transfer data + + //Enable interrupt enable events to occur + // EVT1 do not need interrupt mask, use Raw interrupt + //MmioWrite32 ((SdMmcBaseAddr + MSHCI_INTMSK), CmdInterruptEnableVal); + + // 7. trasfer data + + //8. Send a command + cmd_flags = (Cmd & 0x3F); + if(Cmd & (RSPTYP48 | RSPTYP48B | RSPTYP136)) + { + cmd_flags |= CMD_RESP_EXP_BIT; + if(Cmd & RSPTYP136) + cmd_flags |= CMD_RESP_LENGTH_BIT; + } + + if((Cmd==CMD17)|(Cmd==CMD18)|(Cmd==CMD8)) + { + cmd_flags |= CMD_DATA_EXP_BIT; + //DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Read\n")); + } + + if((Cmd==CMD24)|(Cmd==CMD25)) + { + cmd_flags |= CMD_DATA_EXP_BIT | CMD_RW_BIT; + //DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Write\n")); + + } + + if (Cmd & ENCMDCRC) + { + cmd_flags |= CMD_CHECK_CRC_BIT; + } + cmd_flags |= (CMD_STRT_BIT | CMD_USE_HOLD_REG | CMD_WAIT_PRV_DAT_BIT|CMD_SENT_AUTO_STOP_BIT); + //cmd_flags |= (CMD_STRT_BIT | CMD_USE_HOLD_REG | CMD_WAIT_PRV_DAT_BIT); + DEBUG ((EFI_D_INFO, "CMD flag = 0x%x\n", cmd_flags)); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), cmd_flags); + MicroSecondDelay(1); + + //9. Check for the Raw interrupt + //wait for command complete by busy waiting. + for (RetryCount; RetryCount<MAX_RETRY_COUNT; RetryCount++) + { + MmcStatus = MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS); + if (MmcStatus & INTMSK_CDONE) + { + break; + } + } + + if (RetryCount == MAX_RETRY_COUNT) + { + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd timeout CMD:%d RINT:0x%x\n",(Cmd&0x3F) ,MmcStatus)); + return EFI_TIMEOUT; + } + + if(MmcStatus & INTMSK_RTO) + { + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Response timeout CMD:%d RINT:0x%x\n", (Cmd & 0x3F),MmcStatus)); + return EFI_TIMEOUT; + + } + else if (MmcStatus & INTMSK_RE) + { + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Response Error RINT:0x%x\n", MmcStatus)); + return EFI_TIMEOUT; + } + else if(MmcStatus & INTMSK_RCRC) + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Response CRC Err RINT:0x%x\n", MmcStatus)); + else if(MmcStatus & INTMSK_DCRC) + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Data CRC Err RINT:0x%x\n", MmcStatus)); + else if(MmcStatus & INTMSK_HLE) + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd HLE Err RINT:0x%x\n", MmcStatus)); + else if(MmcStatus & INTMSK_SBE) + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd SBE Err RINT:0x%x\n", MmcStatus)); + else if(MmcStatus & INTMSK_EBE) + DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd EBE Err RINT:0x%x\n", MmcStatus)); + + return EFI_SUCCESS; +} + +/** +Super block size : 4MB (16GB density) +Argument (Boot Size) =(Number of Super Block for boot partition) / 2 + +**/ +EFI_STATUS MSHC_BOOT_Partition(UINT32 bootsize, UINT32 rpmbsize) +{ + UINTN CmdArgument; + EFI_STATUS Status = RETURN_SUCCESS; + UINT32 BootSize, RPMBSize; + + /* Only use this command for raw eMMC moviNAND */ + /* Enter backdoor mode */ + CmdArgument = 0xefac62ec; + Status = MSHC_SendCmd (CMD62, CMD62_INT_EN, CmdArgument); + + /* Boot partition changing mode */ + CmdArgument = 0xcbaea7; + Status = MSHC_SendCmd (CMD62, CMD62_INT_EN, CmdArgument); + + //BootSize = ((bootsize*1024)/128); + BootSize = (bootsize*2); + + /* Arg: boot partition size */ + CmdArgument = BootSize; + Status = MSHC_SendCmd (CMD62, CMD62_INT_EN, CmdArgument); + + //RPMBSize = ((rpmbsize*1024)/128); + RPMBSize = (rpmbsize*2); + + /* Arg: RPMB partition size */ + CmdArgument = RPMBSize; + Status = MSHC_SendCmd (CMD62, CMD62_INT_EN, CmdArgument); + + return Status; + +} + +EFI_STATUS MSHC_EMMC_Boot_Open() +{ + UINTN CmdArgument; + EFI_STATUS Status = RETURN_SUCCESS; + + DEBUG ((EFI_D_INFO, "emmc open\n" )); + /* Boot ack enable, boot partition enable , boot partition access */ + CmdArgument = ((3<<24)|(179<<16)|(((1<<6)|(1<<3)|(1<<0))<<8)); + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, CmdArgument); + if (!EFI_ERROR(Status)) + { + /* 4bit transfer mode at booting time. */ + CmdArgument = ((3<<24)|(177<<16)|((1<<0)<<8)); + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) + { + DEBUG ((EFI_D_ERROR, "emmc open fail 2nd CMD6\n" )); + } + } + else + { + DEBUG ((EFI_D_ERROR, "emmc open fail first CMD6\n" )); + } + + return Status; +} + +EFI_STATUS MSHC_EMMC_Boot_Close() +{ + UINTN CmdArgument; + EFI_STATUS Status = RETURN_SUCCESS; + + DEBUG ((EFI_D_INFO, "emmc close\n" )); + CmdArgument = ((3<<24)|(179<<16)|(((1<<6)|(1<<3)|(0<<0))<<8)); + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) + { + DEBUG ((EFI_D_ERROR, "emmc close fail \n" )); + } + return Status; +} + + +void PrintCardInfo() +{ + DEBUG ((EFI_D_INFO, "MSHC::READ_BL_LEN %d\n", gCardInfo.CSDData.READ_BL_LEN)); + DEBUG ((EFI_D_INFO, "MSHC::CSize %d\n", gCardInfo.CSDData.C_SIZELow2 | (gCardInfo.CSDData.C_SIZEHigh10 << 2))); + DEBUG ((EFI_D_INFO, "MSHC::MULTI %d\n", gCardInfo.CSDData.C_SIZE_MULT)); + +} + + +#define EXT_CSD_SIZE 128 +UINT32 Ext_csd[EXT_CSD_SIZE]; +VOID GetEXTCSD() +{ + gCardInfo.NumBlocks = 0; + gCardInfo.TotalNumBlocks = 30801920; + + UINTN cmdarg = 0; + EFI_STATUS Status = EFI_SUCCESS; + + cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_HS_TIMING << 16) | + (0 << 8); + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, cmdarg); + + cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH << 16) | + (EXT_CSD_BUS_WIDTH_1 << 8); + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, cmdarg); + + cmdarg = 0; + Status = MSHC_SendCmd (CMD8, CMD8_INT_EN, cmdarg); + + gCardInfo.BlockSize = BLEN_512BYTES; + + if (!EFI_ERROR(Status)) + { + DEBUG ((EFI_D_INFO, "MSHC::EXT CSD \n")); + //PrepareTransfer(&Ext_csd[0], 1, READ); + //MSHC_ReadDMA(&Ext_csd[0], 1); + MSHC_ReadFIFO(EXT_CSD_SIZE, &Ext_csd[0]); + gCardInfo.NumBlocks = Ext_csd[EXT_CSD_SEC_CNT/4]; + gCardInfo.Extcsd.boot_size_multi = Ext_csd[BOOT_SIZE_MULTI/4]; + gCardInfo.Extcsd.boot_size_multi = (gCardInfo.Extcsd.boot_size_multi>>16)&0xff; + //MicroSecondDelay(5000); + + DEBUG ((EFI_D_INFO, "MSHC::num blocks %d\n", gCardInfo.NumBlocks)); + DEBUG ((1, "MSHC::eMMC Size:%dMB\n", (gCardInfo.NumBlocks/2048))); + DEBUG ((1, "MSHC::Boot partition Size:%dMB\n", ((gCardInfo.TotalNumBlocks-gCardInfo.NumBlocks)/2048))); + DEBUG ((EFI_D_INFO, "MSHC::Ext CSD boot block %d\n", (gCardInfo.Extcsd.boot_size_multi))); + + } + else + { + gCardInfo.NumBlocks = 0x1D4C000; + DEBUG ((EFI_D_ERROR, "MSHC:: default block number : 0x1D4C000")); + } + +} + + +EFI_STATUS +PerformCardIdenfication ( + VOID + ) +{ + EFI_STATUS Status; + UINTN CmdArgument = 0; + //UINTN Response = 0; + //UINTN RetryCount = 0; + UINTN TempRes0,TempRes1,TempRes2,TempRes3; + //BOOLEAN SDCmd8Supported = FALSE; + UINT32 SdMmcBaseAddr; + int timeout = MAX_RETRY_COUNT; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + gCardInfo.CardType = MMC_CARD; + + //1. Send CMD0 command. go to IDLE + Status = MSHC_SendCmd (CMD0, CMD0_INT_EN, CmdArgument); + + // 2. Send CMD1 while OCR is not busy and get OCR register + do { + CmdArgument = OCR_HCS | MMC_VDD_32_33 | MMC_VDD_33_34; + Status = MSHC_SendCmd (CMD1, CMD1_INT_EN, CmdArgument); + + if (EFI_ERROR(Status)) + { + DEBUG ((EFI_D_ERROR, "MSHC::CMD1 fails.\n")); + } + + MicroSecondDelay(100); + } while (!(MmioRead32 (SdMmcBaseAddr + MSHCI_RESP0)& OCR_BUSY) && timeout--); + + if (timeout <= 0) + { + DEBUG ((EFI_D_ERROR, "MSHC::CMD1 OCR busy timeout.\n")); + return EFI_DEVICE_ERROR; + } + DEBUG ((EFI_D_INFO, "MSHC::CMD1 OCR 0x%x\n", MmioRead32(SdMmcBaseAddr + MSHCI_RESP0))); + + ((UINT32 *) &(gCardInfo.OCRData))[0] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)); + + //3. send CMD2 to get CID register + CmdArgument = 0; + Status = MSHC_SendCmd (CMD2, CMD2_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD2 fails. Status: %x\n", Status)); + return Status; + } + + DEBUG ((EFI_D_INFO, "CMD2 response: %x %x %x %x\n", MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)), \ + MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1)), \ + MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2)), \ + MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3)))); + + TempRes0 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)); + TempRes1 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1)); + TempRes2 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2)); + TempRes3 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3)); + + //Parse CID register data. + ParseCardCIDData(TempRes0 << 8, (TempRes1 << 8) | (TempRes0 >> 24), + (TempRes2 << 8) | (TempRes1 >> 24), (TempRes3 << 8) | (TempRes2 >> 24)); + + //4. send CMD3 to get RCA register + CmdArgument = 0; + Status = MSHC_SendCmd (CMD3, CMD3_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD3 fails. Status: %x\n", Status)); + return Status; + } + + //Set RCA for the detected card. RCA is CMD3 response. + DEBUG ((EFI_D_INFO, "MSHC::CMD3 RCA 0x%x\n", MmioRead32(SdMmcBaseAddr + MSHCI_RESP0))); + gCardInfo.RCA = (MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)) >> 16); + DEBUG ((EFI_D_INFO, "CMD3 response: RCA %x\n", gCardInfo.RCA)); + + gBS->Stall(1000); //Need Debug by wprkfgur + + return EFI_SUCCESS; +} + + +EFI_STATUS +GetCardSpecificData ( + VOID + ) +{ + EFI_STATUS Status; + UINTN CmdArgument; + UINTN TempRes[4],i; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + //Send CMD9 to retrieve CSD. + CmdArgument = gCardInfo.RCA << 16; + Status = MSHC_SendCmd (CMD9, CMD9_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD9 fails. Status: %x\n", Status)); + return Status; + } + + TempRes[0] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)); + TempRes[1] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1)); + TempRes[2] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2)); + TempRes[3] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3)); + + //Populate 128-bit CSD register data. + for (i = 0 ; i < 4; i++) { + ((UINT32 *)&(gCardInfo.CSDData))[i] = TempRes[i]; + } + + DEBUG ((EFI_D_INFO, "CMD9 response: %x %x %x %x\n", ((UINT32 *)&(gCardInfo.CSDData))[0], ((UINT32 *)&(gCardInfo.CSDData))[1], ((UINT32 *)&(gCardInfo.CSDData))[2], ((UINT32 *)&(gCardInfo.CSDData))[3])); + return Status; +} + +EFI_STATUS +PerformCardConfiguration ( + VOID + ) +{ + UINTN CmdArgument = 0; + EFI_STATUS Status; + UINT32 SdMmcBaseAddr; + //UINTN FifoCount = 0; + //UINTN Count=0; + UINT32 OMval; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + OMval = MmioRead32(0x10040000); + DEBUG ((EFI_D_INFO, "MSHC::OM read 0x%x \n", OMval)); + + //Send CMD7 + CmdArgument = gCardInfo.RCA << 16; + Status = MSHC_SendCmd (CMD7, CMD7_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD7 fails. Status: %x\n", Status)); + return Status; + } + + //Send CMD16 to set the block length + //CmdArgument = gCardInfo.BlockSize; + CmdArgument = BLEN_512BYTES; + Status = MSHC_SendCmd (CMD16, CMD16_INT_EN, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD16 fails. Status: %x\n", Status)); + return Status; + } + + if(OMval!=OM_EMMC) + { + GetEXTCSD(); + if(gCardInfo.Extcsd.boot_size_multi!= MSHC_BOOT_SIZE_MULTI) + { + MSHC_BOOT_Partition(MSHC_BOOT_SIZE, MSHC_RPMB_SIZE); + DEBUG ((EFI_D_INFO, "MSHC::Doing Boot partition \n")); + } + else + { + DEBUG ((EFI_D_INFO, "MSHC::Alread boot partition \n", Status)); + } + } + else + { + DEBUG ((1, "MSHC::eMMC booting \n")); + gCardInfo.TotalNumBlocks = 30801920; + gCardInfo.NumBlocks = 30588928; + } + + // set device into 4-bit data bus mode + //Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, 0x2); + // set device into 8-bit data bus mode + CmdArgument = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH <<16) | + (EXT_CSD_BUS_WIDTH_8_DDR <<8); + Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, CmdArgument); + if (!EFI_ERROR (Status)) { + // Set host controler into 8-bit mode + MmioOr32 ((SdMmcBaseAddr + MSHCI_CTYPE), CARD_WIDTH8); + //MmioOr32 ((SdMmcBaseAddr + MSHCI_CTYPE), CARD_WIDTH14); + DEBUG ((EFI_D_INFO, "8-bit mode\n")); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ReadBlockData ( + IN EFI_BLOCK_IO_PROTOCOL *This, + OUT VOID *Buffer, + IN UINTN BlockCount + ) +{ + EFI_STATUS Status = EFI_INVALID_PARAMETER; + UINTN DataSize = This->Media->BlockSize/4; + + DEBUG ((EFI_D_INFO, "MSHC::ReadBlockData start \n")); + + if(MSHC_operation_mode == MSHC_FIFO) + { + Status = MSHC_ReadFIFO(DataSize, Buffer); + } + + else if(MSHC_operation_mode == MSHC_IDMA) + { + Status = MSHC_ReadDMA(Buffer, BlockCount); + } + + return Status; +} + + +EFI_STATUS +WriteBlockData ( + IN EFI_BLOCK_IO_PROTOCOL *This, + OUT VOID *Buffer, + IN UINTN BlockCount + ) +{ + EFI_STATUS Status = EFI_INVALID_PARAMETER; + UINTN DataSize = This->Media->BlockSize/4; + + if(MSHC_operation_mode == MSHC_FIFO) + { + Status = MSHC_WriteFIFO(DataSize, Buffer); + } + else if(MSHC_operation_mode == MSHC_IDMA) + { + Status = MSHC_WriteDMA(Buffer, BlockCount); + } + + return Status; +} + +EFI_STATUS +EraseBlockData ( + IN UINT32 Partition, + IN UINTN StartBlock, + IN UINTN NumBlock + ) +{ + UINTN cmdarg = 0; + EFI_STATUS status = EFI_SUCCESS; + + if(Partition!=MSHC_BOOT_PARTITION) + { + DEBUG ((EFI_D_ERROR, "EraseBlockData failed \n")); + status = EFI_UNSUPPORTED; + goto Exit; + } + + /* MMC High Capacity erase minimum size is 512KB */ + if (NumBlock < 1024) { + if (NumBlock < 512) + NumBlock = 1; + else + NumBlock = 2; + } else { + if (0 == (NumBlock%1024)) { + NumBlock = (NumBlock / 1024); + } else { + NumBlock = (NumBlock / 1024) + 1; + } + } + DEBUG ((EFI_D_INFO, "EraseBlockData start:%d, Numblock:%d\n", StartBlock, NumBlock)); + + cmdarg = StartBlock; + status = MSHC_SendCmd (CMD35, 0, cmdarg); + if(status!=EFI_SUCCESS) + { + DEBUG ((EFI_D_ERROR, "EraseBlockData CMD35 failed \n")); + status = EFI_DEVICE_ERROR; + goto Exit; + } + + cmdarg = StartBlock + NumBlock; + status = MSHC_SendCmd (CMD36, 0, cmdarg); + if(status!=EFI_SUCCESS) + { + DEBUG ((EFI_D_ERROR, "EraseBlockData CMD36 failed \n")); + status = EFI_DEVICE_ERROR; + goto Exit; + } + + cmdarg = 0; + status = MSHC_SendCmd (CMD38, 0, cmdarg); + if(status!=EFI_SUCCESS) + { + DEBUG ((EFI_D_ERROR, "EraseBlockData CMD38 failed \n")); + status = EFI_DEVICE_ERROR; + goto Exit; + } + + Exit: + + return status; +} + + +EFI_STATUS +TransferBlock ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Lba, + IN OUT VOID *Buffer, + IN UINTN BlockCount, + IN OPERATION_TYPE OperationType + ) +{ + EFI_STATUS Status; + UINTN Cmd = 0; + UINTN CmdInterruptEnable = 0; + UINTN CmdArgument = 0; + + // 1. FIFO reset + // MSHC_SendCmd do the fifo reset + + // 2. prepare transfer + + DEBUG ((EFI_D_INFO, "SDHC::TransferBlock : Lba = %d, Buffer = 0x%x, Type = %d\n", Lba, Buffer, OperationType)); + //Populate the command information based on the operation type. + if (OperationType == READ) + { + if(BlockCount>1) + { + Cmd = CMD18; //multi block read + CmdInterruptEnable = CMD18_INT_EN; + } + else + { + Cmd = CMD17; //Single block read + CmdInterruptEnable = CMD17_INT_EN; + } + + } + else if (OperationType == WRITE) + { + if(BlockCount>1) + { + Cmd = CMD25; //multi block write + CmdInterruptEnable = CMD25_INT_EN; + } + else + { + Cmd = CMD24; //Single block write + CmdInterruptEnable = CMD24_INT_EN; + } + } + PrepareTransfer(Buffer, BlockCount, OperationType); + + //Set command argument based on the card access mode (Byte mode or Block mode) + if (gCardInfo.OCRData.AccessMode & BIT1) { + CmdArgument = Lba; + } else { + CmdArgument = Lba * This->Media->BlockSize; + } + + //Send Command. + Status = MSHC_SendCmd (Cmd, CmdInterruptEnable, CmdArgument); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "CMD%d fails. Status: %x\n", (Cmd&0x3F), Status)); + return Status; + } + + DEBUG ((EFI_D_INFO, "CMD%d succeed! \n", (Cmd&0x3F))); + + //Read or Write data. + if (OperationType == READ) { + Status = ReadBlockData (This, Buffer, BlockCount); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n")); + return Status; + } + } else if (OperationType == WRITE) { + Status = WriteBlockData (This, Buffer, BlockCount); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n")); + return Status; + } + } + + return EFI_SUCCESS; +} + +BOOLEAN +CardPresent ( + VOID + ) +{ + return TRUE; +} + +EFI_STATUS +DetectCard ( + VOID + ) +{ + EFI_STATUS Status; + //UINT32 SdMmcBaseAddr; + + //DEBUG ((EFI_D_INFO, "===================================\n")); + DEBUG ((EFI_D_INFO, "===MSHC: Version %a ===\n", DateInformation)); + //DEBUG ((EFI_D_INFO, "===================================\n")); + + //SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + if (!CardPresent ()) { + return EFI_NO_MEDIA; + } + + //Initialize MMC host controller clocks. + Status = InitializeMSHC (); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status)); + return Status; + } + + // EVT1 InitializeSDHC do the SW Reset + //Soft reset for all. + //MmioWrite32((SdMmcBaseAddr + SDHC_SWRST_OFFSET), SRA); + //gBS->Stall(1000); + //while ((MmioRead32 ((SdMmcBaseAddr + SDHC_SWRST_OFFSET)) & SRA) != 0x0); + + //Set the clock frequency to 400KHz. + UpdateMSHCClkFrequency (MSHC_CLK_400); + + //Card idenfication + Status = PerformCardIdenfication (); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "No MMC/SD card detected.\n")); + return Status; + } + + //Get CSD (Card specific data) for the detected card. + Status = GetCardSpecificData(); + if (EFI_ERROR(Status)) { + return Status; + } + + //Configure the card in data transfer mode. + Status = PerformCardConfiguration(); + if (EFI_ERROR(Status)) { + return Status; + } + + //Patch the Media structure. + gSDMMCMedia.LastBlock = (gCardInfo.NumBlocks - 1); + //gSDMMCMedia.BlockSize = gCardInfo.BlockSize; + gSDMMCMedia.BlockSize = 512; + gSDMMCMedia.ReadOnly = 0; + gSDMMCMedia.MediaPresent = TRUE; + gSDMMCMedia.MediaId++; + + UpdateMSHCClkFrequency(MSHC_CLK_50M); + DEBUG ((EFI_D_INFO, "SD Card Media Change on Handle 0x%08x\n", gImageHandle)); + + return Status; +} + + +EFI_STATUS +SdReadWrite ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Lba, + OUT VOID *Buffer, + IN UINTN BufferSize, + IN OPERATION_TYPE OperationType + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN RetryCount = 0; + UINTN BlockCount; + UINTN BytesToBeTranferedThisPass = 0; + UINTN BytesRemainingToBeTransfered=0; + EFI_TPL OldTpl; + //BOOLEAN Update; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + if(gMediaChange==TRUE) + { + Status = DetectCard(); + gMediaChange = FALSE; + gCardInit = TRUE; + } + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "MSHC::Card initialization fail .\n")); + gCardInit = FALSE; + goto Done; + } + +if(gCardInit) +{ + DEBUG ((EFI_D_INFO, "MSHC::SdReadWrite is called Buffersize:%d \n", BufferSize)); + + if (Buffer == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (Lba > This->Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + DEBUG ((EFI_D_ERROR, "MSHC::SdReadWrite EFI_INVALID_PARAMETER\n")); + goto Done; + } + + if ((BufferSize % This->Media->BlockSize) != 0) { + Status = EFI_BAD_BUFFER_SIZE; + DEBUG ((EFI_D_ERROR, "MSHC::SdReadWrite EFI_BAD_BUFFER_SIZE\n")); + goto Done; + } + + //Check if the data lines are not in use. + while ((RetryCount++ < MAX_RETRY_COUNT) && (MmioRead32 ((SdMmcBaseAddr + MSHCI_STATUS)) & DATA_BUSY)); + if (RetryCount == MAX_RETRY_COUNT) { + Status = EFI_TIMEOUT; + DEBUG ((EFI_D_ERROR, "MSHC::SdReadWrite EFI_TIMEOUT\n")); + goto Done; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + BytesRemainingToBeTransfered = BufferSize; + + if(MSHC_operation_mode == MSHC_IDMA) + { + while (BytesRemainingToBeTransfered > 0) { + // Turn OFF DMA path until it is debugged + BytesToBeTranferedThisPass = (BytesRemainingToBeTransfered >= MAX_MSHC_TRANSFER_SIZE) ? MAX_MSHC_TRANSFER_SIZE : BytesRemainingToBeTransfered; + //BytesToBeTranferedThisPass = This->Media->BlockSize; + + BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize; + Status = TransferBlock (This, Lba, Buffer,BlockCount, OperationType); + + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status)); + goto DoneRestoreTPL; + } + + BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass; + Lba += BlockCount; + Buffer = (UINT8 *)Buffer + (This->Media->BlockSize*BlockCount); + DEBUG ((EFI_D_INFO, "SdReadWrite::Buf:0x%x, ToBe:0x%x Rema:0x%x \n", BufferSize, BytesToBeTranferedThisPass, BytesRemainingToBeTransfered)); + + } + } + else + { + while (BytesRemainingToBeTransfered > 0) { + // Turn OFF DMA path until it is debugged + // BytesToBeTranferedThisPass = (BytesToBeTranferedThisPass >= MAX_SDHC_TRANSFER_SIZE) ? MAX_SDHC_TRANSFER_SIZE : BytesRemainingToBeTransfered; + BytesToBeTranferedThisPass = This->Media->BlockSize; + + BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize; + + if (BlockCount > 1) { + // Status = DmaBlocks (This, Lba, Buffer, BlockCount, OperationType); + } else { + //Transfer a block worth of data. + Status = TransferBlock (This, Lba, Buffer, BlockCount,OperationType); + + } + + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status)); + goto DoneRestoreTPL; + } + + BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass; + Lba += BlockCount; + Buffer = (UINT8 *)Buffer + This->Media->BlockSize; + } + + } + + +DoneRestoreTPL: + + gBS->RestoreTPL (OldTpl); + +Done: + + return Status; +} +else + return EFI_TIMEOUT; + + +} + + +/** + + Reset the Block Device. + + + + @param This Indicates a pointer to the calling context. + + @param ExtendedVerification Driver may perform diagnostics on reset. + + + + @retval EFI_SUCCESS The device was reset. + + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + + not be reset. + + + +**/ +EFI_STATUS +EFIAPI +MSHCReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + DEBUG ((EFI_D_INFO, " MSHC::MSHCReset is called\n")); + MSHC_reset_all(); + return EFI_SUCCESS; +} + + +/** + + Read BufferSize bytes from Lba into Buffer. + + + + @param This Indicates a pointer to the calling context. + + @param MediaId Id of the media, changes every time the media is replaced. + + @param Lba The starting Logical Block Address to read from + + @param BufferSize Size of Buffer, must be a multiple of device block size. + + @param Buffer A pointer to the destination buffer for the data. The caller is + + responsible for either having implicit or explicit ownership of the buffer. + + + + @retval EFI_SUCCESS The data was read correctly from the device. + + @retval EFI_DEVICE_ERROR The device reported an error while performing the read. + + @retval EFI_NO_MEDIA There is no media in the device. + + @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device. + + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + + or the buffer is not on proper alignment. + +EFI_STATUS + +**/ + + +#define EMMC_TEST 0 +#if EMMC_TEST +#define EMMC_TEST_SIZE (MAX_MSHC_TRANSFER_SIZE+1024) +UINT32 bWrite[EMMC_TEST_SIZE]; +UINT32 bRead[EMMC_TEST_SIZE]; +//INTN EFIAPI CompareMem (IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length) +//two buffers are identical, then 0 is returned. Otherwise, the value returned is the first mismatched byte + +void MSHC_Test( IN EFI_BLOCK_IO_PROTOCOL *This) +{ + UINTN i=0; + UINTN Count; + INTN ret; + EFI_STATUS Status; + DEBUG ((EFI_D_INFO, "MSHC::Read Write test %dB\n", EMMC_TEST_SIZE)); + + for(i=0; i<EMMC_TEST_SIZE; i++) + { + bWrite[i]=i; + } + +//multi + for(Count=100; Count<102; Count++) + { + //Lba=n; + //DEBUG ((EFI_D_INFO, "MSHC::Read Write test : %d\n", Count)); + ZeroMem (&bRead[0], sizeof(bRead)); + DEBUG ((EFI_D_INFO, "ZR : 0x%x, 0x%x, 0x%x, 0x%x\n", + bRead[0], bRead[1], bRead[2], bRead[3])); + + Status = SdReadWrite (This, (UINTN)Count, &bWrite[0], EMMC_TEST_SIZE, WRITE); + Status = SdReadWrite (This, (UINTN)Count, &bRead[0], EMMC_TEST_SIZE, READ); + + DEBUG ((EFI_D_INFO, "W: 0x%x, 0x%x, 0x%x, 0x%x ", + bWrite[0], bWrite[1], bWrite[2], bWrite[3])); + DEBUG ((EFI_D_INFO, "R : 0x%x, 0x%x, 0x%x, 0x%x\n", + bRead[0], bRead[1], bRead[2], bRead[3])); + + ret = CompareMem(&bRead[0],&bWrite[0],EMMC_TEST_SIZE); + + if(ret==0) + DEBUG ((1, "MSHC::Read Write OK!!\n")); + else + DEBUG ((1, "MSHC::Read Write Failed bWrite[%d]=0x%x : bRead[%d]=0x%x\n", ret, bWrite[ret], ret, bRead[ret])); + + + } + + +} +#endif + + +#define FVB_TEST 0 + +#if FVB_TEST +#define FVB_TEST_SIZE 1336//(64) +#define FVB_Offset 64 //0 +UINT32 FVB_Read[512*3]; +UINT32 FVB_Write[512*3]; +UINT32 Temp[512*3]; +void FVB_Test(IN EFI_BLOCK_IO_PROTOCOL *This) +{ + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *Fvbhandle; + EFI_STATUS status = EFI_SUCCESS; + EFI_LBA Lba = 10; + UINTN NumBytes=FVB_TEST_SIZE; + UINT32 i; + INTN ret; + UINTN Offset=FVB_Offset; + //EFI_FVB_ATTRIBUTES_2 *Attribute=NULL; + UINTN blocksize=0, numofblocks=0; + UINTN EraseStartBlock=10, EraseNumBlocks=5; + EFI_PHYSICAL_ADDRESS *Address=NULL; + + + Fvbhandle = (EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *)This; + DEBUG ((1, "FVB_Test Start \n")); + + status = SdReadWrite (This, 0, &Temp[0], 512, READ); + if(status!=EFI_SUCCESS) + { + DEBUG ((1, "FVB_Test Card Init Failed !!\n")); + goto Exit; + } + + for(i=0; i<512; i++) + { + FVB_Write[i]=i; + } + ZeroMem (&FVB_Read[0], 512); + + //DEBUG ((1, "FVB_Test FvbGetAttributes \n")); + //FvbGetAttributes(Fvbhandle, Attribute); + FvbGetPhysicalAddress(Fvbhandle, Address); + FvbGetBlockSize(Fvbhandle, 0, &blocksize, &numofblocks); + DEBUG ((1, "FVB_Test erase\n")); + FvbEraseBlocks(Fvbhandle, EraseStartBlock, EraseNumBlocks, EFI_LBA_LIST_TERMINATOR); + + DEBUG ((1, "FVB_Test Offset : %d Num : %d\n", Offset, NumBytes)); + status = FvbWrite(Fvbhandle, Lba, Offset, &NumBytes, (UINT8 *)&FVB_Write[Offset]); + if(status!=EFI_SUCCESS) + { + DEBUG ((1, "FVB_Test write fail !!\n")); + goto Exit; + } + + status = FvbRead(Fvbhandle, Lba, Offset, &NumBytes, (UINT8 *)&FVB_Read[0]); + if(status!=EFI_SUCCESS) + { + DEBUG ((1, "FVB_Test read fail !!\n")); + goto Exit; + } + + DEBUG ((1, "FVB W: 0x%x, 0x%x, 0x%x, 0x%x ", + FVB_Write[Offset], FVB_Write[Offset+1], FVB_Write[Offset+2], FVB_Write[Offset+3])); + DEBUG ((1, "FVB R : 0x%x, 0x%x, 0x%x, 0x%x\n", + FVB_Read[0], FVB_Read[1], FVB_Read[2], FVB_Read[3])); + + ret = CompareMem(&FVB_Write[Offset], &FVB_Read[0], FVB_TEST_SIZE); + + if(ret==0) + DEBUG ((1, "MSHC::FVB_Test OK!!\n")); + else + DEBUG ((1, "MSHC::ERROR !!! FVB_Test Failed bWrite[%d]=0x%x : bRead[%d]=0x%x\n", ret, FVB_Write[ret], ret, FVB_Read[ret])); + + Exit: + if(status!=EFI_SUCCESS) + DEBUG ((1, "FVB_Test fail !!\n")); + +} + +#endif + + + +EFI_STATUS +EFIAPI +MSHCReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status=EFI_SUCCESS; + DEBUG ((EFI_D_INFO, "MSHC::MSHCReadBlocks : MediaId = %x, Lba = %d, BufferSize = %d, Buffer = 0x%x\n", + MediaId, (UINTN)Lba, BufferSize, Buffer)); + + Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ); + +#if 0 +#if FVB_TEST + FVB_Test(This); +#else +#if EMMC_TEST + MSHC_Test(This); +#else + //Perform Read operation. + Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ); +#endif +#endif //#if FVB_TEST +#endif + + return Status; + +} + + +/** + + Write BufferSize bytes from Lba into Buffer. + + + + @param This Indicates a pointer to the calling context. + + @param MediaId The media ID that the write request is for. + + @param Lba The starting logical block address to be written. The caller is + + responsible for writing to only legitimate locations. + + @param BufferSize Size of Buffer, must be a multiple of device block size. + + @param Buffer A pointer to the source buffer for the data. + + + + @retval EFI_SUCCESS The data was written correctly to the device. + + @retval EFI_WRITE_PROTECTED The device can not be written to. + + @retval EFI_DEVICE_ERROR The device reported an error while performing the write. + + @retval EFI_NO_MEDIA There is no media in the device. + + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. + + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + + or the buffer is not on proper alignment. + + + +**/ + + +EFI_STATUS +EFIAPI +MSHCWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; +#if EMMC_TEST + UINT32 Count=0; + UINT32 ret; +#endif + + DEBUG ((EFI_D_INFO, "MSHC::MSHCWriteBlocks : MediaId = 0x%x, Lba = %d, BufferSize = %d, Buffer = 0x%x\n", + MediaId, (UINTN)Lba, BufferSize, Buffer)); + + //Perform write operation. + Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, WRITE); + + +#if 0 +#if EMMC_TEST + Count = (BufferSize >= MAX_MSHC_TRANSFER_SIZE) ? MAX_MSHC_TRANSFER_SIZE : BufferSize; + DEBUG ((1, "\nMSHC::Read Write Test [0x%x] Start \n", Count)); + ZeroMem (&bRead[0], sizeof(bRead)); + CopyMem(&bWrite[0], (VOID *)Buffer, Count); + Status = SdReadWrite (This, (UINTN)Lba, &bRead[0], Count, READ); + DEBUG ((1, "W : 0x%x, 0x%x, 0x%x, 0x%x\n", + bWrite[7], bWrite[8], bWrite[9], bWrite[10])); + + DEBUG ((1, "R : 0x%x, 0x%x, 0x%x, 0x%x\n", + bRead[7], bRead[8], bRead[9], bRead[10])); + + ret = CompareMem(&bRead[0],&bWrite[0],Count); + + if(ret==0) + DEBUG ((1, "MSHC::Read Write Test OK!!\n")); + else + DEBUG ((1, "MSHC::Read Write Test Failed -.- bRead[%d]=0x%x bWrite[%d]=0x%x \n", ret, bRead[ret], ret, bWrite[ret])); + +#endif +#endif + + + return Status; + +} + + +/** + + Flush the Block Device. + + + + @param This Indicates a pointer to the calling context. + + + + @retval EFI_SUCCESS All outstanding data was written to the device + + @retval EFI_DEVICE_ERROR The device reported an error while writting back the data + + @retval EFI_NO_MEDIA There is no media in the device. + + + +**/ +EFI_STATUS +EFIAPI +MSHCFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + DEBUG ((EFI_D_INFO, "MSHC::MSHCFlushBlocks is called\n")); + return EFI_SUCCESS; +} + + +EFI_BLOCK_IO_PROTOCOL gBlockIo = { + EFI_BLOCK_IO_INTERFACE_REVISION, // Revision + &gSDMMCMedia, // *Media + MSHCReset, // Reset + MSHCReadBlocks, // ReadBlocks + MSHCWriteBlocks, // WriteBlocks + MSHCFlushBlocks // FlushBlocks +}; + + +EFI_STATUS +EFIAPI +MSHCInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + ZeroMem (&gCardInfo, sizeof (CARD_INFO)); + +//Publish BlockIO. + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiBlockIoProtocolGuid, &gBlockIo, + &gEfiDevicePathProtocolGuid, &gMSHCDevicePath, + NULL + ); + + DEBUG ((EFI_D_INFO, "MSHC::MSHCInitialize:0x%x\n", Status)); + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.h new file mode 100755 index 000000000..e410d669e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.h @@ -0,0 +1,308 @@ +/** @file + + Copyright (c) 2011, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _MSHCDXE_H_ +#define _MSHCDXE_H_ + +#include <Uefi.h> + +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseMemoryLib.h> +#include <Protocol/BlockIo.h> +#include <Protocol/DevicePath.h> +#include <Protocol/FirmwareVolumeBlock.h> + +#include "eMMCDxe_5250.h" +#include "eMMCDxe_CMD.h" + +/** +eMMC partition Gaia EVT1 + +boot partition-1 : 100M store BL1, BL2, UEFI, TZSW +boot partition-2 : 100M not used +RPMB : 16M for secure team +General purpose-1 : not used +General purpose-2 : not used +General purpose-3 : not used +General purpose-4 : not used + +boot partition-1 start offset +BL1: 0 +BL2: 16 +UEFI : 32 +TZSW : 2592~3104 +NV data area : 3200 +NV data for security team : 3200 +NV data for general purpose : 3400 +**/ + +#define MSHC_BOOT_SIZE 100 +#define MSHC_RPMB_SIZE 0 +#define MSHC_BOOT_SIZE_MULTI (MSHC_BOOT_SIZE*2) +#define MSHC_BOOT_SECURE_OFFSET 3200 +#define MSHC_BOOT_SECURE_SIZE 512 // 256k + +#define MSHC_BOOT_PARTITION 0 +#define MSHC_RPMB_PARTITION 1 +#define MSHC_USER_PARTITION 2 + +#define BLEN_512BYTES (0x200) +#define BLKSIZE_1 (0x1) + +#define OM_EMMC 0x8 + +#define MAX_RETRY_COUNT (100000) +#define MMC_REFERENCE_CLK (96000000) +#define MSHC_CLK_400 (400) +#define MSHC_CLK_25M (25000) +#define MSHC_CLK_50M (50000) + +#define OCR_BUSY 0x80000000 +#define OCR_HCS 0x40000000 + +#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ +#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ +#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ +#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ +#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ +#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ +#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ +#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ +#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ +#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ +#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ +#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ +#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ +#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ +#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ +#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ +#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ + + +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in EXT_CSD byte + addressed by index which are + 1 in value field */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in EXT_CSD byte + addressed by index, which are + 1 in value field */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target byte to value */ +/* + * EXT_CSD fields + */ + +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define BOOT_SIZE_MULTI 226 /* RO */ +#define PARTITIONING_SUPPORT 160 /* RO */ + +/* + * EXT_CSD field definitions + */ + +/* Card */ +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ +#define EXT_CSD_CARD_TYPE_52_DDR_18_30 (1<<2) /* Card can run at 52MHz DDR 1.8V or 3V */ +#define EXT_CSD_CARD_TYPE_52_DDR_12 (1<<3) /* Card can run at 52MHz DDR 1.2V */ + +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ +#define EXT_CSD_BUS_WIDTH_4_DDR 5 /* Card is in 4 bit DDR mode */ +#define EXT_CSD_BUS_WIDTH_8_DDR 6 /* Card is in 8 bit DDR mode */ + + +typedef struct { + UINT32 hs_max_dtr; + UINT32 sectors; + UINT32 boot_size_multi; //226 + UINT32 Partitioning_Support; //160 +}mmc_ext_csd; + + +typedef struct { + UINT32 Reserved0: 7; // 0 + UINT32 V170_V195: 1; // 1.70V - 1.95V + UINT32 V200_V260: 7; // 2.00V - 2.60V + UINT32 V270_V360: 9; // 2.70V - 3.60V + UINT32 RESERVED_1: 5; // Reserved + UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode) + UINT32 Busy: 1; // This bit is set to LOW if the card has not finished the power up routine +}OCR; + +typedef struct { + UINT32 NOT_USED; // 1 [0:0] + UINT32 CRC; // CRC7 checksum [7:1] + UINT32 MDT; // Manufacturing date [19:8] + UINT32 RESERVED_1; // Reserved [23:20] + UINT32 PSN; // Product serial number [55:24] + UINT8 PRV; // Product revision [63:56] + UINT8 PNM[5]; // Product name [64:103] + UINT16 OID; // OEM/Application ID [119:104] + UINT8 MID; // Manufacturer ID [127:120] +}CID; + +typedef struct { + UINT8 NOT_USED: 1; // Not used, always 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] + + UINT8 RESERVED_1: 2; // Reserved [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + + UINT16 RESERVED_2: 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 RESERVED_3: 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + + UINT32 WP_GRP_SIZE: 7; // Write protect group size [38:32] + UINT32 SECTOR_SIZE: 7; // Erase sector size [45:39] + UINT32 ERASE_BLK_EN: 1; // Erase single block enable [46:46] + UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47] + UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50] + UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53] + UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56] + UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59] + UINT32 C_SIZELow2: 2; // Device size [63:62] + + UINT32 C_SIZEHigh10: 10;// Device size [73:64] + UINT32 RESERVED_4: 2; // Reserved [75:74] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT32 CCC: 12;// Card command classes [95:84] + + UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96] + UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC ; // Data read access-time 1 [119:112] + + UINT8 RESERVED_5: 6; // Reserved [125:120] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +}CSD; + + + +typedef struct { + UINT8 NOT_USED: 1; // Not used, always 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] + UINT8 RESERVED_1: 2; // Reserved [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + UINT16 RESERVED_2: 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 RESERVED_3: 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + UINT16 WP_GRP_SIZE: 7; // Write protect group size [38:32] + UINT16 SECTOR_SIZE: 7; // Erase sector size [45:39] + UINT16 ERASE_BLK_EN: 1; // Erase single block enable [46:46] + UINT16 RESERVED_4: 1; // Reserved [47:47] + UINT32 C_SIZELow16: 16;// Device size [69:48] + UINT32 C_SIZEHigh6: 6; // Device size [69:48] + UINT32 RESERVED_5: 6; // Reserved [75:70] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + UINT16 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT16 CCC: 12;// Card command classes [95:84] + UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96] + UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC ; // Data read access-time 1 [119:112] + UINT8 RESERVED_6: 6; // 0 [125:120] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +}CSD_SDV2; + +typedef enum { + UNKNOWN_CARD, + MMC_CARD, //MMC card + SD_CARD, //SD 1.1 card + SD_CARD_2, //SD 2.0 or above standard card + SD_CARD_2_HIGH, //SD 2.0 or above high capacity card + SD_CARD_MAX +} CARD_TYPE; + + + +typedef enum { + MSHC_IDMA, + MSHC_FIFO +}MSHC_OPERATION_MODE; + +typedef struct { + UINT16 RCA; + UINTN BlockSize; + UINTN NumBlocks; + UINTN TotalNumBlocks; + UINTN ClockFrequencySelect; + CARD_TYPE CardType; + OCR OCRData; + CID CIDData; + CSD CSDData; + mmc_ext_csd Extcsd; +} CARD_INFO; + + +EFI_STATUS +DetectCard (VOID); +void mshci_reset_fifo(void); + +extern EFI_BLOCK_IO_PROTOCOL gBlockIo; +extern EFI_BLOCK_IO_MEDIA gSDMMCMedia; +extern CARD_INFO gCardInfo; +extern BOOLEAN gCardInit; + +extern EFI_STATUS +SdReadWrite ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Lba, + OUT VOID *Buffer, + IN UINTN BufferSize, + IN OPERATION_TYPE OperationType + ); +EFI_STATUS +EraseBlockData ( + IN UINT32 Partition, + IN UINTN StartBlock, + IN UINTN NumBlock + ); + + + +#endif + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.inf new file mode 100755 index 000000000..45e9ed1a4 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.inf @@ -0,0 +1,64 @@ +#/** @file +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = eMMCDxe + FILE_GUID = 39ad4d3f-dee8-4708-ac4e-46c8335c48a6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = MSHCInitialize + + +[Sources.common] + eMMCDxe.c + eMMCDxe_5250.c + +[Packages] + MdePkg/MdePkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + SamsungPlatformPkg/SamsungPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + SamsungPlatformPkg/ArndaleBoardPkg/ArndaleBoardPkg.dec + ArmPkg/ArmPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + IoLib + TimerLib + MemoryAllocationLib + UncachedMemoryAllocationLib + +[Guids] + +[Protocols] + gEfiBlockIoProtocolGuid + gEfiDevicePathProtocolGuid + gSamsungPlatformGpioProtocolGuid ## GPIO Protocol + gEfiFirmwareVolumeBlockProtocolGuid + +[Pcd] + gExynosPkgTokenSpaceGuid.PcdCmuBase + gExynosPkgTokenSpaceGuid.PcdSdMmcCH0Base + gExynosPkgTokenSpaceGuid.PcdEmmcDMABufferBase + +[FixedPcd.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + +[Depex] + TRUE + + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.c new file mode 100755 index 000000000..511b079d4 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.c @@ -0,0 +1,721 @@ +/** @file + MMC/SD Card driver for Secure Digital Host Controller + + This driver always produces a BlockIo protocol but it starts off with no Media + present. A TimerCallBack detects when media is inserted or removed and after + a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the + media to be detected (or removed) and the BlockIo Media structure will get + updated. No MMC/SD Card harward registers are updated until the first BlockIo + ReadBlocks/WriteBlocks after media has been insterted (booting with a card + plugged in counts as an insertion event). + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + + +#include <Library/TimerLib.h> +#include <Library/PcdLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UncachedMemoryAllocationLib.h> +#include <Protocol/ExynosGpio.h> +#include <Platform/ArmPlatform.h> +#include <Platform/Exynos5250.h> +#include <Platform/Arndale5250.h> + + +#include "eMMCDxe.h" + +//#undef EFI_D_INFO +//#define EFI_D_INFO 1 + +#define DMA_UNCACHE_ALLOC 0 +#if DMA_UNCACHE_ALLOC +UINT32 *DMABuffer; +#endif +void MSHC_reset_all(void) +{ + int count; + volatile int ctl_val=0; + UINT32 SdMmcBaseAddr; + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + /* Wait max 100 ms */ + count = 10000; + + /* before reset ciu, it should check DATA0. if when DATA0 is low and + it resets ciu, it might make a problem */ + while ((MmioRead32 ((SdMmcBaseAddr + MSHCI_STATUS)) & (1<<9))){ + if (count == 0) { + DEBUG ((EFI_D_ERROR, "MMC controller never released. \n")); + return; + } + count--; + MicroSecondDelay(1); + } + + // Reset CIU + ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL)); + ctl_val |= CTRL_RESET; + MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val); + + //Reset FIFO + MSHC_reset_fifo(); + + //Reset DMA + ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL)); + ctl_val |= DMA_RESET; + MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val); + + //Set auto stop CMD + ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL)); + ctl_val |= SEND_AS_CCSD; + MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val); + +} + + +void MSHC_Set_DDR(int BusMode) +{ + + UINT32 clkphase; + //clkphase = 0x03030002; //cmd response error at 50M RINT=0x46 error, RE and CD, RCRC + //clkphase = 0x03020001; //data read error at 50M SBE + UINT32 SdMmcBaseAddr; + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + if(BusMode==BUSMODE_DDR) + { + DEBUG ((EFI_D_INFO, "MSHC DDR .\n")); + MmioWrite32((SdMmcBaseAddr + MSHCI_UHS_REG), UHS_DDR); + clkphase = 0x03020001; + } + else + { + DEBUG ((EFI_D_INFO, "MSHC Non DDR .\n")); + MmioWrite32((SdMmcBaseAddr + MSHCI_UHS_REG), UHS_NON_DDR); + clkphase = 0x03030002; + } + MmioWrite32((SdMmcBaseAddr + MSHCI_CLKSEL), clkphase); + +} + + +void MSHC_5250_init(void) +{ + UINT32 SdMmcBaseAddr; + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + /* Power Enable Register */ + MmioWrite32((SdMmcBaseAddr + MSHCI_PWREN), POWER_ENABLE); + //MSHC_Set_DDR(BUSMODE_DDR); + + MSHC_reset_all(); + + // Initialize FIFO + MmioWrite32((SdMmcBaseAddr + MSHCI_FIFOTH), (MSIZE_8 | TX_WMARK_DEFAULT | RX_WMARK_DEFAULT)); + + /* It clears all pending interrupts */ + MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_ALL); + /* It dose not use Interrupt. Disable all */ + MmioWrite32((SdMmcBaseAddr + MSHCI_INTMSK), 0); + + //UpdateMSHCClkFrequency(MSHC_CLK_400); + + /* Set auto stop command */ + //MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), (1<<10)); + + /* set debounce filter value*/ + MmioWrite32((SdMmcBaseAddr + MSHCI_DEBNCE), (0xfffff)); + + /* clear card type. set 1-bit mode */ + MmioWrite32((SdMmcBaseAddr + MSHCI_CTYPE), 0x0); + + /* set bus mode register for IDMAC */ + MmioWrite32((SdMmcBaseAddr + MSHCI_BMOD), (BMOD_IDMAC_RESET)); + + /* disable all interrupt source of IDMAC */ + MmioWrite32((SdMmcBaseAddr + MSHCI_IDINTEN), (0x0)); + + /* set max timeout */ + MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff)); + + MmioWrite32((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES); + MmioWrite32((SdMmcBaseAddr + MSHCI_CLKSEL), 0x03030002); + +} + +EFI_STATUS +InitializeMSHC ( + VOID + ) +{ + + EFI_STATUS Status; + EXYNOS_GPIO *Gpio; + UINT32 CumBaseAddr; + //UINT32 SdMmcBaseAddr; + UINT32 i, clock; + volatile UINT32 ctl_val; + + + Status = gBS->LocateProtocol(&gSamsungPlatformGpioProtocolGuid, NULL, (VOID **)&Gpio); + ASSERT_EFI_ERROR(Status); + + CumBaseAddr = PcdGet32(PcdCmuBase); + //SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + //MmioWrite32((SdMmcBaseAddr + SDHC_SWRST_OFFSET), SRA); + + // Set Clock Source for using MPLL + ctl_val = MmioRead32((CumBaseAddr + CLK_SRC_FSYS_OFFSET)); + ctl_val &= ~(0xf); + ctl_val |= (0x6); + MmioWrite32((CumBaseAddr + CLK_SRC_FSYS_OFFSET), ctl_val); + //MmioAndThenOr32 ((CumBaseAddr + CLK_SRC_FSYS_OFFSET), ~(0xF), (0x6)); + + // CLK mask + ctl_val = MmioRead32((CumBaseAddr + CLK_SRC_MASK_FSYS_OFFSET)); + ctl_val |= (0x1); + MmioWrite32((CumBaseAddr + CLK_SRC_MASK_FSYS_OFFSET), ctl_val); + + // CLK gating + ctl_val = MmioRead32((CumBaseAddr + CLK_GATE_IP_FSYS_OFFSET)); + ctl_val |= (0x1<<12); + MmioWrite32((CumBaseAddr + CLK_GATE_IP_FSYS_OFFSET), ctl_val); + + + /* MMC2 clock div */ + clock = 800; //MPLL in MHz + for(i=0; i<= 0xf; i++) + { + if((clock / (i+1)) <= 90) { + MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xF << 0), (i << 0)); + break; + } + } + + + // 2. GPIO setting + // Set GPIO for using SD/MMC CH0 for eMMC + Gpio->Set(Gpio,SD_0_CLK,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_0_CMD,GPIO_MODE_SPECIAL_FUNCTION_2); + //Gpio->Set(Gpio,SD_0_CDn,GPIO_MODE_SPECIAL_FUNCTION_2); + + //Set CDn as HIGH + Gpio->Set(Gpio,SD_0_CDn, GPIO_MODE_OUTPUT_1); + + + Gpio->Set(Gpio,SD_0_DATA0,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_0_DATA1,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_0_DATA2,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_0_DATA3,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_0_DATA4,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_0_DATA5,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_0_DATA6,GPIO_MODE_SPECIAL_FUNCTION_2); + Gpio->Set(Gpio,SD_0_DATA7,GPIO_MODE_SPECIAL_FUNCTION_2); + + Gpio->SetPull(Gpio,SD_0_CLK,GPIO_PULL_NONE); + Gpio->SetPull(Gpio,SD_0_CMD,GPIO_PULL_NONE); + Gpio->SetPull(Gpio,SD_0_CDn,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_0_DATA0,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_0_DATA1,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_0_DATA2,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_0_DATA3,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_0_DATA4,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_0_DATA5,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_0_DATA6,GPIO_PULL_UP); + Gpio->SetPull(Gpio,SD_0_DATA7,GPIO_PULL_UP); + +Gpio->SetStrength(Gpio,SD_0_CLK,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_CMD,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_CDn,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_DATA0,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_DATA1,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_DATA2,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_DATA3,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_DATA4,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_DATA5,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_DATA6,GPIO_DRV_3X); +Gpio->SetStrength(Gpio,SD_0_DATA7,GPIO_DRV_3X); + + MSHC_5250_init(); +#if DMA_UNCACHE_ALLOC + DMABuffer = (UINT32 *)UncachedAllocatePool(EMMC_DMA_PHYSICAL_BUFFER_SIZE/2); + if(DMABuffer==NULL) + { + DEBUG ((EFI_D_ERROR, "MSHC::DMA alloc failed \n")); + } +#endif + return EFI_SUCCESS; + +} + +void MSHC_reset_fifo(void) +{ + volatile int ctl_val=0; + UINT32 SdMmcBaseAddr; + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + //Reset FIFO + ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL)); + ctl_val |= FIFO_RESET; + MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val); + +} + + +VOID MSHC_clock_onoff (int value) +{ + volatile UINT32 loop_count = 0x100000; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + if(value==CLK_ENABLE) + { + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKENA), (0x1<<0)); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), 0); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK); + do { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_CMD) & CMD_STRT_BIT)==0) + break; + loop_count--; + } while (loop_count); + } + else + { + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKENA), (0x0<<0)); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), 0); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK); + do { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_CMD) & CMD_STRT_BIT)==0) + break; + loop_count--; + } while (loop_count); + } + + if (loop_count == 0) { + DEBUG ((EFI_D_ERROR, "MSHC::clockonoff : Clk = %d\n", value)); + } + +} + + +VOID +UpdateMSHCClkFrequency ( + UINTN NewCLK + ) +{ + UINT32 CumBaseAddr; + UINT32 SdMmcBaseAddr; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + CumBaseAddr = PcdGet32(PcdCmuBase); + + // Disable all clocks to not provide the clock to the card +//(CONFIG_CPU_EXYNOS5250_EVT1) + MSHC_clock_onoff(CLK_DISABLE); + //MmioAnd32 ((SdMmcBaseAddr + CLKCON_OFFSET), ~(0xF)); + + //Set new clock frequency. + if (NewCLK == MSHC_CLK_400) + { + DEBUG ((EFI_D_INFO, "MSHC::CLK=400.\n")); + // MPLL=800, cclk_in=100, 100M/250=400k + //MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0xE008); + MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0x1); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 125); + } + else if (NewCLK == MSHC_CLK_25M) + { + DEBUG ((EFI_D_INFO, "MSHC::CLK=25M.\n")); + // DDR mode use CLKDIV MPLL = 800, SCLK = 400, cclk_in=100M + MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0x1); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 2); + } + else if(NewCLK == MSHC_CLK_50M) + { + DEBUG ((EFI_D_INFO, "MSHC::CLK=50M.\n")); + // DDR mode use CLKDIV MPLL = 800, SCLK = 400, cclk_in=100M + MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0x1); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 1); + + MSHC_Set_DDR(BUSMODE_DDR); + //MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK); + } + +//#if defined(CONFIG_CPU_EXYNOS5250_EVT1) + MSHC_clock_onoff(CLK_ENABLE); + //MmioOr32 ((SdMmcBaseAddr + CLKCON_OFFSET), ICE); + + //Poll till Internal Clock Stable + //while ((MmioRead32 ((SdMmcBaseAddr + CLKCON_OFFSET)) & ICS) != ICS); + + //Set Clock enable to 0x1 to provide the clock to the card + //MmioOr32 ((SdMmcBaseAddr + CLKCON_OFFSET), CCE); + +} + +extern MSHC_OPERATION_MODE MSHC_operation_mode; +void mshci_set_mdma_desc(UINT8 *desc_vir, UINT8 *desc_phy, + UINT32 des0, UINT32 des1, UINT32 des2) +{ + ((struct mshci_idmac *)(desc_vir))->des0 = des0; + ((struct mshci_idmac *)(desc_vir))->des1 = des1; + ((struct mshci_idmac *)(desc_vir))->des2 = des2; + ((struct mshci_idmac *)(desc_vir))->des3 = (UINT32)desc_phy + + sizeof(struct mshci_idmac); +} + + +VOID +PrepareTransfer ( +IN OUT VOID *Buffer, UINTN BlockCount, IN OPERATION_TYPE OperationType + ) +{ + UINT32 SdMmcBaseAddr; + UINT32 EmmcDMABufferBase; + volatile UINT32 MshcRegValue; + struct mshci_idmac *pdesc_dmac; + UINT32 des_flag; + UINTN i=0; + UINT32 ByteCnt=0; + UINT32 BlockCnt=BlockCount; +// UINT32 MSH_uDES_A_0, MSH_uDES_A_1, MSH_uDES_A_2, MSH_uDES_A_3; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); +#if DMA_UNCACHE_ALLOC + EmmcDMABufferBase = (UINT32)DMABuffer; +#else + EmmcDMABufferBase = PcdGet32(PcdEmmcDMABufferBase); +#endif + //pdesc_dmac = idmac_desc; + pdesc_dmac = (struct mshci_idmac *)EmmcDMABufferBase; + + if(MSHC_operation_mode==MSHC_FIFO) + { + MSHC_reset_fifo(); + + // 1. enable interrupt mode + MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_CTRL); + MshcRegValue |= INT_ENABLE; + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CTRL), MshcRegValue); + + // 2. DDR mode + + // 3. set BLKSIZE + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES); + //MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLKSIZE_1); + + // 4. set BYTCNT + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BYTCNT), BLEN_512BYTES); + + //Setting Data timeout counter value to max value. + MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff)); + + } + else if(MSHC_operation_mode==MSHC_IDMA) + { + ZeroMem ((VOID *)EmmcDMABufferBase, PHY_BUF_OFFSET);//20120608 + if(OperationType==WRITE) + { + CopyMem((VOID *)(EmmcDMABufferBase+PHY_BUF_OFFSET), (VOID *)Buffer, BlockCount*BLEN_512BYTES); + //DEBUG ((EFI_D_INFO, "MSHC_DMA prepare WRITE:%d Block \n", BlockCount)); + } + else + { + //DEBUG ((EFI_D_INFO, "MSHC_DMA prepare READ:%d Block \n", BlockCount)); + } + + MSHC_reset_fifo(); + + //IDMA reset + MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_BMOD); + MshcRegValue |= (BMOD_IDMAC_RESET); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BMOD), MshcRegValue); + + + // 1. enable IDMA at CTRL + MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_CTRL); + MshcRegValue &= ~(INT_ENABLE); + MshcRegValue |= (ENABLE_IDMAC); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_CTRL), MshcRegValue); + + + // 2. enable IDMA at BMODE + //Set Block Size and Block count. + MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_BMOD); + MshcRegValue |= (BMOD_IDMAC_ENABLE | BMOD_IDMAC_FB); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BMOD), MshcRegValue); + + // interrupt enable + MmioWrite32((SdMmcBaseAddr + MSHCI_IDINTEN), (0x337)); + +#if 0 +#if 0 + // set descriptor singlechain + des_flag = 0x8000000E; + MSH_uDES_A_0 = (EmmcDMABufferBase+0x02F000); + MSH_uDES_A_1 = (EmmcDMABufferBase+0x02F004); + MSH_uDES_A_2 = (EmmcDMABufferBase+0x02F008); + MSH_uDES_A_3 = (EmmcDMABufferBase+0x02F00C); + MmioWrite32(MSH_uDES_A_0, 0x8000000E); + MmioWrite32(MSH_uDES_A_1, (ByteCount)); + MmioWrite32(MSH_uDES_A_2, (EmmcDMABufferBase+PHY_BUF_OFFSET)); + MmioWrite32(MSH_uDES_A_3, MSH_uDES_A_0); +#endif + + + + des_flag = (MSHCI_IDMAC_OWN | MSHCI_IDMAC_FS | MSHCI_IDMAC_DIC | MSHCI_IDMAC_LD); + mshci_set_mdma_desc((UINT8 *)pdesc_dmac, + (UINT8 *)pdesc_dmac, + des_flag, ByteCount, + ((UINT32)(EmmcDMABufferBase + PHY_BUF0_OFFSET))); + + MmioWrite32 ((SdMmcBaseAddr + MSHCI_DBADDR), (UINT32)pdesc_dmac); + + + +#else + + for(i=0; ; i++) + { + // set descriptor multichain + des_flag = (MSHCI_IDMAC_OWN|MSHCI_IDMAC_CH); + des_flag |= (i==0) ? MSHCI_IDMAC_FS:0; + if(BlockCnt<=8) + { + //DEBUG ((EFI_D_INFO, "DESC LD\n")); + des_flag |= (MSHCI_IDMAC_LD); + mshci_set_mdma_desc((UINT8 *)pdesc_dmac, + //(UINT8 *)pdesc_dmac, + (UINT8 *)(EmmcDMABufferBase-sizeof(struct mshci_idmac)), + des_flag, BlockCnt*BLEN_512BYTES, + ((UINT32)((EmmcDMABufferBase + PHY_BUF_OFFSET)+(UINT32)(i*PHY_BUF_SIZE)))); + break; + + } + //DEBUG ((EFI_D_INFO, "DESC FS\n")); + mshci_set_mdma_desc((UINT8 *)pdesc_dmac, + (UINT8 *)pdesc_dmac, + des_flag, BLEN_512BYTES*8, + ((UINT32)((EmmcDMABufferBase + PHY_BUF_OFFSET)+(UINT32)(i*PHY_BUF_SIZE)))); + + BlockCnt -=8; + pdesc_dmac++; + + } + + MmioWrite32 ((SdMmcBaseAddr + MSHCI_DBADDR), (UINT32)EmmcDMABufferBase); + +#endif + + // 3. set BLKSIZE + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES); + + // 4. set BYTCNT + ByteCnt = (BlockCount*BLEN_512BYTES); + MmioWrite32 ((SdMmcBaseAddr + MSHCI_BYTCNT), ByteCnt); + + //Setting Data timeout counter value to max value. + MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff)); + DEBUG ((EFI_D_INFO, "Block:%d BYTCNT:0x%x ByteCnt:0x%x\n", BlockCount,MmioRead32(SdMmcBaseAddr + MSHCI_BYTCNT), ByteCnt)); + + } + +} + +EFI_STATUS MSHC_ReadFIFO(IN UINTN Size32, OUT VOID *Buffer) +{ + EFI_STATUS Status; + UINT32 SdMmcBaseAddr; + UINTN *DataBuffer = Buffer; + UINTN BufSize=Size32; + UINTN FifoCount=0; + UINTN Count=0; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + //Check controller status to make sure there is no error. + + while (BufSize) + { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_RXDR) + { + + //Read block worth of data. + FifoCount = GET_FIFO_COUNT(MmioRead32 (SdMmcBaseAddr + MSHCI_STATUS)); + DEBUG ((EFI_D_INFO, "MSHC::ReadBlock DTO FIFO:%d\n", FifoCount)); + for (Count = 0; Count < FifoCount; Count++) + { + *DataBuffer++ = MmioRead32 (SdMmcBaseAddr + MSHCI_FIFO); + } + MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_RXDR); + BufSize -= FifoCount; + } + + else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO) + { + + //Read block worth of data. + FifoCount = GET_FIFO_COUNT(MmioRead32 (SdMmcBaseAddr + MSHCI_STATUS)); + DEBUG ((EFI_D_INFO, "MSHC::ReadBlock DTO FIFO:%d\n", FifoCount)); + for (Count = 0; Count < FifoCount; Count++) + { + *DataBuffer++ = MmioRead32 (SdMmcBaseAddr + MSHCI_FIFO); + } + MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_DTO); + BufSize -= FifoCount; + } + + else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & (INTMSK_DCRC|INTMSK_DRTO|INTMSK_HTO|INTMSK_FRUN)) + { + DEBUG ((EFI_D_INFO, "MSHC::ReadBlock Error RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS))); + return EFI_DEVICE_ERROR; + } + + } + + if(BufSize==0) + { + Status = EFI_SUCCESS; + } + else + { + Status = EFI_BAD_BUFFER_SIZE; + } + return Status; +} + +EFI_STATUS MSHC_WriteFIFO(IN UINTN Size32, IN VOID *Buffer) +{ + UINT32 SdMmcBaseAddr; + UINTN *DataBuffer = Buffer; + UINTN BufSize=Size32; + UINTN Count=0; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + + if(BufSize>FIFO_SIZE) + { + DEBUG ((EFI_D_INFO, "MSHC::Error MSHC_WriteFIFO Bad buffer size\n")); + return EFI_BAD_BUFFER_SIZE; + } + + //Write block worth of data. + for (Count = 0; Count < BufSize; Count++) + { + MmioWrite32 ((SdMmcBaseAddr + MSHCI_FIFO), *DataBuffer++); + } + return EFI_SUCCESS; + +} + +/*typedef +VOID +CopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + );*/ + +EFI_STATUS MSHC_ReadDMA(OUT VOID *Buffer, IN UINTN BlockCount) +{ + EFI_STATUS Status; + UINT32 SdMmcBaseAddr; + UINT32 EmmcDMABufferBase; + UINTN Count=MAX_RETRY_COUNT; + //UINT32 MshcRegValue; + //UINT32 TransferSize=0; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); +#if DMA_UNCACHE_ALLOC + EmmcDMABufferBase = (UINT32)DMABuffer; +#else + EmmcDMABufferBase = PcdGet32(PcdEmmcDMABufferBase); +#endif + //Check controller status to make sure there is no error. + + while (Count) + { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO) + { + //TransferSize = MmioRead32 (SdMmcBaseAddr + MSHCI_TBBCNT); + CopyMem((VOID *)Buffer, (VOID *)(EmmcDMABufferBase+PHY_BUF_OFFSET), BlockCount*BLEN_512BYTES); + DEBUG ((EFI_D_INFO, "MSHC_ReadDMA Over %d Blocks\n", BlockCount)); + break; + } + else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & (DATA_ERR|DATA_TOUT)) + { + DEBUG ((EFI_D_ERROR, "MSHC_ReadDMA Err RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS))); + } + + else + { + Count--; + MicroSecondDelay(1); + DEBUG ((EFI_D_INFO, ".\n")); + } + + } + + if(Count!=0) + { + Status = EFI_SUCCESS; + } + else + { + DEBUG ((EFI_D_ERROR, "MSHC_ReadDMA bad buffer size RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS))); + Status = EFI_BAD_BUFFER_SIZE; + MmioWrite32 ((SdMmcBaseAddr + MSHCI_PLDMND), 7); + + } + return Status; +} + +EFI_STATUS MSHC_WriteDMA(IN VOID *Buffer, IN UINTN BlockCount) +{ + EFI_STATUS Status; + UINT32 SdMmcBaseAddr; + UINTN Count=MAX_RETRY_COUNT; + + SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base); + //Check controller status to make sure there is no error. + + while (Count) + { + if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO) + { + DEBUG ((EFI_D_INFO, "MSHC_writeDMA Over %d blocks\n", BlockCount)); + break; + } + else + { + MicroSecondDelay(1); + Count--; + } + + } + + if(Count!=0) + { + Status = EFI_SUCCESS; + } + else + { + Status = EFI_BAD_BUFFER_SIZE; + MmioWrite32 ((SdMmcBaseAddr + MSHCI_PLDMND), 7); + DEBUG ((EFI_D_ERROR, "MSHC_writeDMA bad buffer size RINT:0x%x \n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS))); + } + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.h new file mode 100755 index 000000000..56638ba44 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.h @@ -0,0 +1,322 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _MSHCDXE_5250_H_ +#define _MSHCDXE_5250_H_ + + +/* + * Controller registers + */ +/*****************************************************/ +/* MSHC Internal Registers */ +/*****************************************************/ + +#define MSHCI_CTRL 0x00 /* Control */ +#define MSHCI_PWREN 0x04 /* Power-enable */ +#define MSHCI_CLKDIV 0x08 /* Clock divider */ +#define MSHCI_CLKSRC 0x0C /* Clock source */ +#define MSHCI_CLKENA 0x10 /* Clock enable */ +#define MSHCI_TMOUT 0x14 /* Timeout */ +#define MSHCI_CTYPE 0x18 /* Card type */ +#define MSHCI_BLKSIZ 0x1C /* Block Size */ +#define MSHCI_BYTCNT 0x20 /* Byte count */ +#define MSHCI_INTMSK 0x24 /* Interrupt Mask */ +#define MSHCI_CMDARG 0x28 /* Command Argument */ +#define MSHCI_CMD 0x2C /* Command */ +#define MSHCI_RESP0 0x30 /* Response 0 */ +#define MSHCI_RESP1 0x34 /* Response 1 */ +#define MSHCI_RESP2 0x38 /* Response 2 */ +#define MSHCI_RESP3 0x3C /* Response 3 */ +#define MSHCI_MINTSTS 0x40 /* Masked interrupt status */ +#define MSHCI_RINTSTS 0x44 /* Raw interrupt status */ +#define MSHCI_STATUS 0x48 /* Status */ +#define MSHCI_FIFOTH 0x4C /* FIFO threshold */ +#define MSHCI_CDETECT 0x50 /* Card detect */ +#define MSHCI_WRTPRT 0x54 /* Write protect */ +#define MSHCI_GPIO 0x58 /* General Purpose IO */ +#define MSHCI_TCBCNT 0x5C /* Transferred CIU byte count */ +#define MSHCI_TBBCNT 0x60 /* Transferred host/DMA to/from byte count */ +#define MSHCI_DEBNCE 0x64 /* Card detect debounce */ +#define MSHCI_USRID 0x68 /* User ID */ +#define MSHCI_VERID 0x6C /* Version ID */ +#define MSHCI_HCON 0x70 /* Hardware Configuration */ +#define MSHCI_UHS_REG 0x74 /* UHS and DDR setting */ +#define MSHCI_BMOD 0x80 /* Bus mode register */ +#define MSHCI_PLDMND 0x84 /* Poll demand */ +#define MSHCI_DBADDR 0x88 /* Descriptor list base address */ +#define MSHCI_IDSTS 0x8C /* Internal DMAC status */ +#define MSHCI_IDINTEN 0x90 /* Internal DMAC interrupt enable */ +#define MSHCI_DSCADDR 0x94 /* Current host descriptor address */ +#define MSHCI_BUFADDR 0x98 /* Current host buffer address */ +#define MSHCI_CLKSEL 0x9C /* Drv/sample clock selection register */ +#define MSHCI_WAKEUPCON 0xA0 /* Wakeup control register */ +#define MSHCI_CLOCKCON 0xA4 /* Clock (delay) control register */ +#define MSHCI_FIFO 0x200 +#define MSHCI_FIFODAT(x) (x) /* FIFO data read write */ + + +/***************************************************** + * Control Register Register + * MSHCI_CTRL - offset 0x00 + *****************************************************/ + +#define CTRL_RESET (0x1<<0) /* Reset DWC_mobile_storage controller */ +#define FIFO_RESET (0x1<<1) /* Reset FIFO */ +#define DMA_RESET (0x1<<2) /* Reset DMA interface */ +#define INT_ENABLE (0x1<<4) /* Global interrupt enable/disable bit */ +#define DMA_ENABLE (0x1<<5) /* DMA transfer mode enable/disable bit */ +#define READ_WAIT (0x1<<6) /* For sending read-wait to SDIO cards */ +#define SEND_IRQ_RESP (0x1<<7) /* Send auto IRQ response */ +#define ABRT_READ_DATA (0x1<<8) +#define SEND_CCSD (0x1<<9) +#define SEND_AS_CCSD (0x1<<10) +#define CEATA_INTSTAT (0x1<<11) +#define CARD_VOLA (0xF<<16) +#define CARD_VOLB (0xF<<20) +#define ENABLE_OD_PULLUP (0x1<<24) +#define ENABLE_IDMAC (0x1<<25) +#define MSHCI_RESET_ALL (0x1) + +/***************************************************** + * Power Enable Register + * MSHCI_PWREN - offset 0x04 + *****************************************************/ +#define POWER_ENABLE (0x1<<0) + +/***************************************************** +* Clock Enable Register +* MSHCI_CLKENA - offset 0x10 +*****************************************************/ +#define CLK_SDMMC_MAX (48000000) /* 96Mhz. it SHOULDBE optimized */ +#define CLK_ENABLE (0x1<<0) +#define CLK_DISABLE (0x0<<0) + + +/***************************************************** + * Interrupt Mask Register + * MSHCI_INTMSK - offset 0x24 + *****************************************************/ +#define INT_MASK (0xFFFF<<0) +#define SDIO_INT_MASK (0xFFFF<<16) +#define SDIO_INT_ENABLE (0x1<<16) + +/* interrupt bits */ +#define INTMSK_ALL 0xFFFFFFFF +#define INTMSK_CDETECT (0x1<<0) +#define INTMSK_RE (0x1<<1) +#define INTMSK_CDONE (0x1<<2) +#define INTMSK_DTO (0x1<<3) +#define INTMSK_TXDR (0x1<<4) +#define INTMSK_RXDR (0x1<<5) +#define INTMSK_RCRC (0x1<<6) +#define INTMSK_DCRC (0x1<<7) +#define INTMSK_RTO (0x1<<8) +#define INTMSK_DRTO (0x1<<9) +#define INTMSK_HTO (0x1<<10) +#define INTMSK_FRUN (0x1<<11) +#define INTMSK_HLE (0x1<<12) +#define INTMSK_SBE (0x1<<13) +#define INTMSK_ACD (0x1<<14) +#define INTMSK_EBE (0x1<<15) +#define INTMSK_DMA (INTMSK_ACD|INTMSK_RXDR|INTMSK_TXDR) + +#define INT_SRC_IDMAC (0x0) +#define INT_SRC_MINT (0x1) + + +/***************************************************** + * Command Register + * MSHCI_CMD - offset 0x2C + *****************************************************/ + +#define CMD_RESP_EXP_BIT (0x1<<6) +#define CMD_RESP_LENGTH_BIT (0x1<<7) +#define CMD_CHECK_CRC_BIT (0x1<<8) +#define CMD_DATA_EXP_BIT (0x1<<9) +#define CMD_RW_BIT (0x1<<10) +#define CMD_TRANSMODE_BIT (0x1<<11) +#define CMD_SENT_AUTO_STOP_BIT (0x1<<12) +#define CMD_WAIT_PRV_DAT_BIT (0x1<<13) +#define CMD_ABRT_CMD_BIT (0x1<<14) +#define CMD_SEND_INIT_BIT (0x1<<15) +#define CMD_CARD_NUM_BITS (0x1F<<16) +#define CMD_SEND_CLK_ONLY (0x1<<21) +#define CMD_READ_CEATA (0x1<<22) +#define CMD_CCS_EXPECTED (0x1<<23) +#define CMD_USE_HOLD_REG (0x1<<29) +#define CMD_STRT_BIT (0x1<<31) +#define CMD_ONLY_CLK (CMD_STRT_BIT | CMD_SEND_CLK_ONLY | \ + CMD_WAIT_PRV_DAT_BIT) + +/***************************************************** + * Raw Interrupt Register + * MSHCI_RINTSTS - offset 0x44 + *****************************************************/ +#define INT_STATUS (0xFFFF<<0) +#define SDIO_INTR (0xFFFF<<16) +#define DATA_ERR (INTMSK_EBE|INTMSK_SBE|INTMSK_HLE|INTMSK_FRUN |\ + INTMSK_EBE |INTMSK_DCRC) +#define DATA_TOUT (INTMSK_HTO|INTMSK_DRTO) +#define DATA_STATUS (DATA_ERR|DATA_TOUT|INTMSK_RXDR|INTMSK_TXDR|INTMSK_DTO) +#define CMD_STATUS (INTMSK_RTO|INTMSK_RCRC|INTMSK_CDONE|INTMSK_RE) +#define CMD_ERROR (INTMSK_RCRC|INTMSK_RTO|INTMSK_RE) + + +/***************************************************** + * Status Register + * MSHCI_STATUS - offset 0x48 + *****************************************************/ +#define FIFO_RXWTRMARK (0x1<<0) +#define FIFO_TXWTRMARK (0x1<<1) +#define FIFO_EMPTY (0x1<<2) +#define FIFO_FULL (0x1<<3) +#define CMD_FSMSTAT (0xF<<4) +#define DATA_3STATUS (0x1<<8) +#define DATA_BUSY (0x1<<9) +#define DATA_MCBUSY (0x1<<10) +#define RSP_INDEX (0x3F<<11) +#define FIFO_COUNT (0x1FFF<<17) +#define DMA_ACK (0x1<<30) +#define DMA_REQ (0x1<<31) +#define FIFO_WIDTH (0x4) +#define FIFO_DEPTH (0x20) +#define FIFO_SIZE (0x80) +#define GET_FIFO_COUNT(x) (((x)&0x3ffe0000)>>17) + + + +/***************************************************** + * FIFO Threshold Watermark Register + * MSHCI_FIFOTH - offset 0x4C + *****************************************************/ +#define TX_WMARK (0xFFF<<0) +#define RX_WMARK (0xFFF<<16) +#define MSIZE_MASK (0x7<<28) + +/* DW DMA Mutiple Transaction Size */ +#define MSIZE_1 (0<<28) +#define MSIZE_4 (1<<28) +#define MSIZE_8 (2<<28) +#define MSIZE_16 (3<<28) +#define MSIZE_32 (4<<28) +#define MSIZE_64 (5<<28) +#define MSIZE_128 (6<<28) +#define MSIZE_256 (7<<28) + +#define TX_WMARK_DEFAULT (0x10<<0) +#define RX_WMARK_DEFAULT (0x10<<16) + +//#define TX_WMARK_DEFAULT (0x40<<0) +//#define RX_WMARK_DEFAULT (0x3F<<16) + + +/***************************************************** + * Bus Mode Register + * MSHCI_UHS_REG - offset 0x74 + *****************************************************/ +#define UHS_DDR (0x1<<16) +#define UHS_NON_DDR (0x0<<16) +#define BUSMODE_DDR 1 +#define BUSMODE_NON_DDR 0 + +/***************************************************** + * Bus Mode Register + * MSHCI_BMOD - offset 0x80 + *****************************************************/ +#define BMOD_IDMAC_RESET (0x1<<0) +#define BMOD_IDMAC_FB (0x1<<1) +#define BMOD_IDMAC_ENABLE (0x1<<7) + +/***************************************************** + * Hardware Configuration Register + * MSHCI_IDSTS - offset 0x8c + *****************************************************/ +#define IDSTS_FSM (0xf<<13) +#define IDSTS_EB (0x7<<10) +#define IDSTS_AIS (0x1<<9) +#define IDSTS_NIS (0x1<<8) +#define IDSTS_CES (0x1<<5) +#define IDSTS_DU (0x1<<4) +#define IDSTS_FBE (0x1<<2) +#define IDSTS_RI (0x1<<1) +#define IDSTS_TI (0x1<<0) + + +/***************************************************** + * Card Type Register + * MSHCI_CTYPE - offset 0x18 + *****************************************************/ +#define CARD_WIDTH14 (0xFFFF<<0) +#define CARD_WIDTH8 (0xFFFF<<16) + +struct mshci_idmac { + UINT32 des0; + UINT32 des1; + UINT32 des2; + UINT32 des3; +#define MSHCI_IDMAC_OWN (1<<31) +#define MSHCI_IDMAC_ER (1<<5) +#define MSHCI_IDMAC_CH (1<<4) +#define MSHCI_IDMAC_FS (1<<3) +#define MSHCI_IDMAC_LD (1<<2) +#define MSHCI_IDMAC_DIC (1<<1) +#define INTMSK_IDMAC_ALL (0x337) +#define INTMSK_IDMAC_ERROR (0x214) +}; + +typedef enum { + READ, + WRITE +} OPERATION_TYPE; + + +/***************************************************** + * DMA Buffer structure + * + * CH0 for eMMC 0x40300000--0x40380000 + * CH2 for SD Card 0x40380000--0x40400000 + + + *****************************************************/ +#define EMMC_DMA_PHYSICAL_BUFFER_BASE 0x40300000 +#define EMMC_DMA_PHYSICAL_BUFFER_SIZE 0x00100000 //1MB +#define PHY_BUF_OFFSET 0x1000 //4K +#define PHY_BUF_SIZE 0x1000 //4K + +#define MAX_MSHC_TRANSFER_SIZE 0x40000 //512blocks, 256KB + + + +/***************************************************** + * External Functions + *****************************************************/ + + +EFI_STATUS InitializeMSHC (VOID); +VOID UpdateMSHCClkFrequency (UINTN NewCLK); +void MSHC_reset_fifo(void); +extern void MSHC_reset_all(void); +extern VOID PrepareTransfer (IN OUT VOID *Buffer, UINTN ByteCount, IN OPERATION_TYPE OperationType); +extern EFI_STATUS MSHC_ReadFIFO(IN UINTN Size32, OUT VOID *Buffer); +extern EFI_STATUS MSHC_WriteFIFO(IN UINTN Size32, IN VOID *Buffer); +void mshci_set_mdma_desc(UINT8 *desc_vir, UINT8 *desc_phy, + UINT32 des0, UINT32 des1, UINT32 des2); +EFI_STATUS MSHC_ReadDMA(OUT VOID *Buffer, IN UINTN BlockCount); +EFI_STATUS MSHC_WriteDMA(IN VOID *Buffer, IN UINTN BlockCount); + + + +#endif + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_CMD.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_CMD.h new file mode 100755 index 000000000..615da0799 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_CMD.h @@ -0,0 +1,165 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _MSHCDXE_CMD_H_ +#define _MSHCDXE_CMD_H_ + + + +#define HosttoCard 0x1 +#define CardtoHost 0x0 + +#define ENDMA BIT0 +#define ENBLKCNT BIT1 +#define RD1WT0 BIT4 +#define MUL1SIN0 BIT5 +#define RSPTYP136 (0x1 << 16) +#define RSPTYP48 (0x2 << 16) +#define RSPTYP48B (0x3 << 16) +#define ENCMDCRC BIT19 +#define ENCMDIDX BIT20 +#define DATAPRNT BIT21 + + +#define CMDCOMP BIT0 +#define TRNSCOMP BIT1 +#define RDYFORWT BIT4 +#define RDYFORRD BIT5 +#define CARDINSERT BIT6 +#define CARDREMOVE BIT7 +#define ERRINT BIT15 +#define CMDTOUTERR BIT16 +#define CMDCRCERR BIT17 +#define CMDEBITERR BIT18 +#define CMDIDXERR BIT19 +#define DATATOUTERR BIT20 +#define DATACRCERR BIT21 +#define DATAEBITERR BIT22 + + + + +/* Command Definitions */ +#define INDX(CMD_INDX) (CMD_INDX & 0x3F) + +#define CMD0 INDX(0) +#define CMD0_INT_EN (CMDCOMP | CMDEBITERR) + +#define CMD1 (INDX(1) | RSPTYP48) +#define CMD1_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD2 (INDX(2) | ENCMDCRC | RSPTYP136) +#define CMD2_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD3 (INDX(3) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD3_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD5 (INDX(5) | RSPTYP48) +#define CMD5_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD7 (INDX(7) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD7_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD8 (INDX(8) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD8_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) +//Reserved(0)[12:31], Supply voltage(1)[11:8], check pattern(0xCE)[7:0] = 0x1CE +#define CMD8_ARG (0x0UL << 12 | BIT8 | 0xCEUL << 0) + +#define CMD9 (INDX(9) | ENCMDCRC | RSPTYP136) +#define CMD9_INT_EN (CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD13 (INDX(13) | RSPTYP48) +#define CMD13_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR) + + +//#define CMD16 (INDX(16) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD16 (INDX(16) | ENCMDIDX | RSPTYP48) +#define CMD16_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD17 (INDX(17) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | RD1WT0) +#define CMD17_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORRD | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR) + +//#define CMD18 (INDX(18) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | MUL1SIN0 | RD1WT0 | ENBLKCNT | ENDMA) +#define CMD18 (INDX(18) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 ) +#define CMD18_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORRD | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR) + +#define CMD23 (INDX(23) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD23_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD24 (INDX(24) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD24_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORWT | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR) + +//#define CMD25 (INDX(25) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | MUL1SIN0 | ENBLKCNT | ENDMA) +#define CMD25 (INDX(25) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD25_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORWT | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR) + +#define CMD35 (INDX(35) | ENCMDCRC | RSPTYP48) +#define CMD36 (INDX(36) | ENCMDCRC | RSPTYP48) +#define CMD38 (INDX(38) |RSPTYP48) + +#define CMD55 (INDX(55) | ENCMDIDX | ENCMDCRC | RSPTYP48) +#define CMD55_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define ACMD41 (INDX(41) | RSPTYP48) +#define ACMD41_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define ACMD6 (INDX(6) | RSPTYP48) +#define ACMD6_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + +#define CMD62 (INDX(62) | RSPTYP48) +#define CMD62_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR) + + + +/* +EFI_STATUS +EFI_SUCCESS 0 + +EFI_LOAD_ERROR 1 +EFI_INVALID_PARAMETER 2 +EFI_UNSUPPORTED 3 +EFI_BAD_BUFFER_SIZE 4 +EFI_BUFFER_TOO_SMALL 5 +EFI_NOT_READY 6 +EFI_DEVICE_ERROR 7 +EFI_WRITE_PROTECTED 8 +EFI_OUT_OF_RESOURCES 9 +EFI_VOLUME_CORRUPTED 10 +EFI_VOLUME_FULL 11 +EFI_NO_MEDIA 12 +EFI_MEDIA_CHANGED 13 +EFI_NOT_FOUND 14 +EFI_ACCESS_DENIED 15 +EFI_NO_RESPONSE 16 +EFI_NO_MAPPING 17 +EFI_TIMEOUT 18 +EFI_NOT_STARTED 19 +EFI_ALREADY_STARTED 20 +EFI_ABORTED 21 +EFI_ICMO_ERROR 22 +EFI_TFTP_ERROR 23 +EFI_PROTOCOL_ERROR 24 +EFI_INCOMPATIBLE_VERSION 25 +EFI_SECURITY_VIOLATION 26 +EFI_CRC_ERROR 27 +EFI_END_OF_MEDIA 28 +EFI_END_OF_FILE 31 +EFI_INVALID_LANGUAGE 32 +EFI_COMPROMISED_DATA 33 + + +*/ + +#endif + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMC_Fvb.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMC_Fvb.c new file mode 100755 index 000000000..ee8d1c902 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMC_Fvb.c @@ -0,0 +1,587 @@ +/** @file + eMMC firmware volume block protocol driver + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/PcdLib.h> +#include <Library/UncachedMemoryAllocationLib.h> + +#include <Protocol/FirmwareVolumeBlock.h> +#include "eMMCDxe.h" + + +//#undef EFI_D_INFO +//#define EFI_D_INFO 1 + + +EFI_FVB_ATTRIBUTES_2 gAttribute = (EFI_FVB2_READ_STATUS|EFI_FVB2_WRITE_STATUS|EFI_FVB2_ALIGNMENT_32); +UINT32 *FVBMemAddr; + +/** + The GetAttributes() function retrieves the attributes and + current settings of the block. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the + attributes and current settings are + returned. Type EFI_FVB_ATTRIBUTES_2 is defined + in EFI_FIRMWARE_VOLUME_HEADER. + + @retval EFI_SUCCESS The firmware volume attributes were + returned. + +**/ + +EFI_STATUS +EFIAPI +FvbGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + *Attributes = gAttribute; + DEBUG ((EFI_D_INFO, "FvbGetAttributes 0x%x\n", gAttribute)); + return EFI_SUCCESS; +} + + +/** + The SetAttributes() function sets configurable firmware volume + attributes and returns the new settings of the firmware volume. + + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Attributes On input, Attributes is a pointer to + EFI_FVB_ATTRIBUTES_2 that contains the + desired firmware volume settings. On + successful return, it contains the new + settings of the firmware volume. Type + EFI_FVB_ATTRIBUTES_2 is defined in + EFI_FIRMWARE_VOLUME_HEADER. + + @retval EFI_SUCCESS The firmware volume attributes were returned. + + @retval EFI_INVALID_PARAMETER The attributes requested are in + conflict with the capabilities + as declared in the firmware + volume header. + +**/ +EFI_STATUS +EFIAPI +FvbSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + gAttribute |= *Attributes; + *Attributes = gAttribute; + DEBUG ((EFI_D_INFO, "FvbSetAttributes 0x%x\n", gAttribute)); + return EFI_SUCCESS; +} + + +/** + The GetPhysicalAddress() function retrieves the base address of + a memory-mapped firmware volume. This function should be called + only for memory-mapped firmware volumes. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Address Pointer to a caller-allocated + EFI_PHYSICAL_ADDRESS that, on successful + return from GetPhysicalAddress(), contains the + base address of the firmware volume. + + @retval EFI_SUCCESS The firmware volume base address was returned. + + @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped. + +**/ +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + UINT32 NVBase = PcdGet32(PcdFlashNvStorageVariableBase); + UINT32 NVSize = PcdGet32(PcdFlashNvStorageVariableSize); + + DEBUG ((EFI_D_INFO, "FvbGetPhysicalAddress Base:0x%x, Size:0x%x\n", NVBase, NVSize)); + + if(FVBMemAddr==NULL) + { + FVBMemAddr = (UINT32 *)UncachedAllocatePool(NVSize); + DEBUG ((EFI_D_INFO, "FvbGetPhysicalAddress MEM Alloc 0x%x\n", FVBMemAddr)); + + if(FVBMemAddr==NULL) + { + DEBUG ((EFI_D_ERROR, "FvbGetPhysicalAddress Alloc failed \n")); + return EFI_UNSUPPORTED; + } + } + else + { + DEBUG ((EFI_D_INFO, "FvbGetPhysicalAddress already Allocated 0x%x \n", FVBMemAddr)); + } + + CopyMem((VOID *)FVBMemAddr, (VOID *)NVBase, NVSize); + Address = (EFI_PHYSICAL_ADDRESS *)FVBMemAddr; + DEBUG ((EFI_D_INFO, "FvbGetPhysicalAddress Addr:0x%x\n", Address)); + return EFI_SUCCESS; +} + + +/** + The GetBlockSize() function retrieves the size of the requested + block. It also returns the number of additional blocks with + the identical size. The GetBlockSize() function is used to + retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER). + + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba Indicates the block for which to return the size. + + @param BlockSize Pointer to a caller-allocated UINTN in which + the size of the block is returned. + + @param NumberOfBlocks Pointer to a caller-allocated UINTN in + which the number of consecutive blocks, + starting with Lba, is returned. All + blocks in this range have a size of + BlockSize. + + + @retval EFI_SUCCESS The firmware volume base address was returned. + + @retval EFI_INVALID_PARAMETER The requested LBA is out of range. + +**/ +EFI_STATUS +EFIAPI +FvbGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +{ + EFI_STATUS status = EFI_SUCCESS; + *BlockSize = gSDMMCMedia.BlockSize; + *NumberOfBlocks = 512; + DEBUG ((EFI_D_INFO, "FvbGetBlockSize numblocks:%d\n", *NumberOfBlocks)); + return status; +} + + + +/** + Reads the specified number of bytes into a buffer from the specified block. + + The Read() function reads the requested number of bytes from the + requested block and stores them in the provided buffer. + Implementations should be mindful that the firmware volume + might be in the ReadDisabled state. If it is in this state, + the Read() function must return the status code + EFI_ACCESS_DENIED without modifying the contents of the + buffer. The Read() function must also prevent spanning block + boundaries. If a read is requested that would span a block + boundary, the read must read up to the boundary but not + beyond. The output parameter NumBytes must be set to correctly + indicate the number of bytes actually read. The caller must be + aware that a read may be partially completed. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba The starting logical block index + from which to read. + + @param Offset Offset into the block at which to begin reading. + + @param NumBytes Pointer to a UINTN. At entry, *NumBytes + contains the total size of the buffer. At + exit, *NumBytes contains the total number of + bytes read. + + @param Buffer Pointer to a caller-allocated buffer that will + be used to hold the data that is read. + + @retval EFI_SUCCESS The firmware volume was read successfully, + and contents are in Buffer. + + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA + boundary. On output, NumBytes + contains the total number of bytes + returned in Buffer. + + @retval EFI_ACCESS_DENIED The firmware volume is in the + ReadDisabled state. + + @retval EFI_DEVICE_ERROR The block device is not + functioning correctly and could + not be read. + +**/ +EFI_STATUS +EFIAPI +FvbRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN OUT UINT8 *Buffer + ) +{ + EFI_BLOCK_IO_PROTOCOL *EFIBlockIO = (EFI_BLOCK_IO_PROTOCOL *)This; + EFI_STATUS status = EFI_SUCCESS; + VOID *TempBuf = NULL; + UINT32 NumBlock; + UINT32 AllocSize=0; + Lba += MSHC_BOOT_SECURE_OFFSET; + + DEBUG ((EFI_D_INFO, "FvbRead Offset : %d, Numbytes : %d\n", Offset, *NumBytes)); + + if(gCardInit==TRUE) + { + if (0 == (*NumBytes%gSDMMCMedia.BlockSize)) + { + NumBlock = (*NumBytes/gSDMMCMedia.BlockSize); + } + else + { + NumBlock = (*NumBytes/gSDMMCMedia.BlockSize) + 1; + } + //DEBUG ((EFI_D_INFO, "FvbRead numblock : %d, BlockSize : %d\n", NumBlock, gSDMMCMedia.BlockSize)); + + AllocSize = NumBlock*gSDMMCMedia.BlockSize; + TempBuf = AllocatePool(AllocSize); + //ZeroMem (TempBuf, NumBlock*gSDMMCMedia.BlockSize); + if(TempBuf==NULL) + { + DEBUG ((EFI_D_ERROR, "FvbRead AllocatePool Failed!!\n")); + status = EFI_DEVICE_ERROR; + goto Exit; + } + + status = SdReadWrite(EFIBlockIO, Lba, TempBuf, AllocSize, READ); + if(status!=EFI_SUCCESS) + { + DEBUG ((EFI_D_ERROR, "FvbRead Failed 0x%x\n", status)); + status = EFI_ACCESS_DENIED; + goto Exit; + } + + CopyMem((VOID *)Buffer, (VOID *)(TempBuf+Offset), *NumBytes); + } + + Exit: + + if (TempBuf != NULL) + { + FreePool(TempBuf); + } + + return status; +} + + +/** + Writes the specified number of bytes from the input buffer to the block. + + The Write() function writes the specified number of bytes from + the provided buffer to the specified block and offset. If the + firmware volume is sticky write, the caller must ensure that + all the bits of the specified range to write are in the + EFI_FVB_ERASE_POLARITY state before calling the Write() + function, or else the result will be unpredictable. This + unpredictability arises because, for a sticky-write firmware + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY + state but cannot flip it back again. Before calling the + Write() function, it is recommended for the caller to first call + the EraseBlocks() function to erase the specified block to + write. A block erase cycle will transition bits from the + (NOT)EFI_FVB_ERASE_POLARITY state back to the + EFI_FVB_ERASE_POLARITY state. Implementations should be + mindful that the firmware volume might be in the WriteDisabled + state. If it is in this state, the Write() function must + return the status code EFI_ACCESS_DENIED without modifying the + contents of the firmware volume. The Write() function must + also prevent spanning block boundaries. If a write is + requested that spans a block boundary, the write must store up + to the boundary but not beyond. The output parameter NumBytes + must be set to correctly indicate the number of bytes actually + written. The caller must be aware that a write may be + partially completed. All writes, partial or otherwise, must be + fully flushed to the hardware before the Write() service + returns. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba The starting logical block index to write to. + + @param Offset Offset into the block at which to begin writing. + + @param NumBytes The pointer to a UINTN. At entry, *NumBytes + contains the total size of the buffer. At + exit, *NumBytes contains the total number of + bytes actually written. + + @param Buffer The pointer to a caller-allocated buffer that + contains the source for the write. + + @retval EFI_SUCCESS The firmware volume was written successfully. + + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an + LBA boundary. On output, NumBytes + contains the total number of bytes + actually written. + + @retval EFI_ACCESS_DENIED The firmware volume is in the + WriteDisabled state. + + @retval EFI_DEVICE_ERROR The block device is malfunctioning + and could not be written. + + +**/ +EFI_STATUS +EFIAPI +FvbWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_BLOCK_IO_PROTOCOL *EFIBlockIO = (EFI_BLOCK_IO_PROTOCOL *)This; + EFI_STATUS status = EFI_SUCCESS; + VOID *TempBuf = NULL; + UINT32 NumBlock; + UINT32 AllocSize=0; + Lba += MSHC_BOOT_SECURE_OFFSET; + + DEBUG ((EFI_D_INFO, "FvbWrite Offset : %d, Numbyte : %d\n", Offset, *NumBytes)); + + if(gCardInit==TRUE) + { + if (0 == (*NumBytes%gSDMMCMedia.BlockSize)) + { + NumBlock = (*NumBytes/gSDMMCMedia.BlockSize); + } + else + { + NumBlock = (*NumBytes/gSDMMCMedia.BlockSize) + 1; + } + //DEBUG ((EFI_D_INFO, "FvbWrite numblock : %d, BlockSize : %d\n", NumBlock, gSDMMCMedia.BlockSize)); + + AllocSize = (NumBlock*gSDMMCMedia.BlockSize); + TempBuf = AllocatePool(AllocSize); + //ZeroMem (TempBuf, NumBlock*gSDMMCMedia.BlockSize); + if(TempBuf==NULL) + { + DEBUG ((EFI_D_ERROR, "FvbWrite AllocatePool Failed!!\n")); + status = EFI_DEVICE_ERROR; + goto Exit; + } + + status = SdReadWrite(EFIBlockIO, Lba, TempBuf, AllocSize, READ); + if(status!=EFI_SUCCESS) + { + DEBUG ((EFI_D_ERROR, "FvbWrite Read Failed 0x%x\n", status)); + status = EFI_DEVICE_ERROR; + goto Exit; + } + + CopyMem((VOID *)(TempBuf+Offset), (VOID *)Buffer, *NumBytes); + + status = SdReadWrite(EFIBlockIO, Lba, TempBuf, AllocSize, WRITE); + if(status!=EFI_SUCCESS) + { + DEBUG ((EFI_D_ERROR, "FvbWrite Write Failed 0x%x\n", status)); + status = EFI_ACCESS_DENIED; + goto Exit; + } + } + else + { + DEBUG ((EFI_D_ERROR, "FvbWrite Error eMMC is not ready\n")); + } + + Exit: + + if (TempBuf != NULL) + { + FreePool(TempBuf); + } + + return status; +} + + +/** + Erases and initializes a firmware volume block. + + The EraseBlocks() function erases one or more blocks as denoted + by the variable argument list. The entire parameter list of + blocks must be verified before erasing any blocks. If a block is + requested that does not exist within the associated firmware + volume (it has a larger index than the last block of the + firmware volume), the EraseBlocks() function must return the + status code EFI_INVALID_PARAMETER without modifying the contents + of the firmware volume. Implementations should be mindful that + the firmware volume might be in the WriteDisabled state. If it + is in this state, the EraseBlocks() function must return the + status code EFI_ACCESS_DENIED without modifying the contents of + the firmware volume. All calls to EraseBlocks() must be fully + flushed to the hardware before the EraseBlocks() service + returns. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL + instance. + + @param ... The variable argument list is a list of tuples. + Each tuple describes a range of LBAs to erase + and consists of the following: + - An EFI_LBA that indicates the starting LBA + - A UINTN that indicates the number of blocks to + erase. + + The list is terminated with an + EFI_LBA_LIST_TERMINATOR. For example, the + following indicates that two ranges of blocks + (5-7 and 10-11) are to be erased: EraseBlocks + (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR); + + @retval EFI_SUCCESS The erase request successfully + completed. + + @retval EFI_ACCESS_DENIED The firmware volume is in the + WriteDisabled state. + @retval EFI_DEVICE_ERROR The block device is not functioning + correctly and could not be written. + The firmware device may have been + partially erased. + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed + in the variable argument list do + not exist in the firmware volume. + +**/ +EFI_STATUS +EFIAPI +FvbEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + ... + ) +{ + EFI_STATUS status = EFI_SUCCESS; + UINTN StartBlock, NumBlock; + UINTN Index; + VA_LIST Marker; + + VA_START (Marker, This); + + for (Index = 0, status = EFI_SUCCESS; !EFI_ERROR (status); Index++) + { + StartBlock = VA_ARG (Marker, UINTN); + NumBlock = VA_ARG (Marker, UINTN); + DEBUG ((EFI_D_INFO, "FvbEraseBlocks start:%d numblock:%d\n", StartBlock, NumBlock)); + + if(StartBlock==0xFFFFFFFF) + { + break; + } + + StartBlock += MSHC_BOOT_SECURE_OFFSET; + /* MMC High Capacity erase minimum size is 512KB */ + status = EraseBlockData(MSHC_BOOT_PARTITION, StartBlock, NumBlock); + } + + VA_END (Marker); + return status; +} + + +// +// Making this global saves a few bytes in image size +// +EFI_HANDLE gFvbHandle = NULL; + + +/// +/// The Firmware Volume Block Protocol is the low-level interface +/// to a firmware volume. File-level access to a firmware volume +/// should not be done using the Firmware Volume Block Protocol. +/// Normal access to a firmware volume must use the Firmware +/// Volume Protocol. Typically, only the file system driver that +/// produces the Firmware Volume Protocol will bind to the +/// Firmware Volume Block Protocol. +/// +EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL gFvbProtocol = { + FvbGetAttributes, + FvbSetAttributes, + FvbGetPhysicalAddress, + FvbGetBlockSize, + FvbRead, + FvbWrite, + FvbEraseBlocks, + /// + /// The handle of the parent firmware volume. + /// + NULL +}; + + +#if 0 +/** + Initialize the state information for the CPU Architectural Protocol + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +FvbDxeInitialize () +{ + EFI_STATUS Status; + + + Status = gBS->InstallMultipleProtocolInterfaces ( + &gFvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, &gFvbProtocol, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // SetVertAddressEvent () + + // GCD Map NAND as RT + + return Status; +} +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec b/SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec new file mode 100755 index 000000000..d4863ced4 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec @@ -0,0 +1,101 @@ +#/** @file +# Arm RealView EB package. +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License which accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = ExynosPkg + PACKAGE_GUID = ec1a4982-4a00-47e7-8df5-69c8ce895427 + PACKAGE_VERSION = 0.1 + +################################################################################ +# +# Include Section - list of Include Paths that are provided by this package. +# Comments are used for Keywords and Module Types. +# +# Supported Module Types: +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION +# +################################################################################ +[Includes.common] + Include # Root include for the package + +[Guids.common] + gExynosPkgTokenSpaceGuid = { 0x70b6655a, 0x7a03, 0x11e0, { 0xbe, 0x19, 0x00, 0x26, 0xb9, 0x73, 0x3e, 0x2c} } + +[PcdsFeatureFlag.common] + +[PcdsFixedAtBuild.common] + + # + # Samsung + # + # Framebuffer Base Address and size + gExynosPkgTokenSpaceGuid.PcdFrameBufferBase|0|UINT32|0x4E000000 + gExynosPkgTokenSpaceGuid.PcdFrameBufferSize|0|UINT32|0x00400000 + + # Memory Partition : Shared memory 1MB (0x4000_0000 -- 0x4010_0000) + gExynosPkgTokenSpaceGuid.PcdSmemBaseAddress|0|UINT32|0x40000000 + gExynosPkgTokenSpaceGuid.PcdSmemSize|0|UINT32|0x00100000 + + # Memory Partition : EMMC DMA buffer Address and Size 1MB (0x4030_0000 -- 0x4040_0000) + gExynosPkgTokenSpaceGuid.PcdEmmcDMABufferBase|0|UINT32|0x40300000 +# gExynosPkgTokenSpaceGuid.PcdEmmcDMABufferSize|0|UINT32|0x00100000 + + ## iRam Base Address and size. + gExynosPkgTokenSpaceGuid.PcdiRamBootBase|0|UINT32|0x00020000 + gExynosPkgTokenSpaceGuid.PcdiRamBootSize|0|UINT32|0x00020001 + + gExynosPkgTokenSpaceGuid.PcdiRamStackBase|0|UINT32|0x00020002 + gExynosPkgTokenSpaceGuid.PcdiRamStackSize|0|UINT32|0x00020003 + + gExynosPkgTokenSpaceGuid.PcdMpSharedArgsBase|0x8ff00000|UINT32|0x00000020 + gExynosPkgTokenSpaceGuid.PcdMpSharedArgsSize|0x00100000|UINT32|0x00000021 + + gExynosPkgTokenSpaceGuid.PcdPeiServicePtrAddr|0|UINT32|0x00000003 + gExynosPkgTokenSpaceGuid.PcdConsoleUartBase|0|UINT32|0x00000004 + gExynosPkgTokenSpaceGuid.PcdWinDebugUartBase|0|UINT32|0x00000005 + gExynosPkgTokenSpaceGuid.PcdCmuBase|0|UINT32|0x00000006 + gExynosPkgTokenSpaceGuid.PcdPWMTimerBase|0|UINT32|0x00000007 + gExynosPkgTokenSpaceGuid.PcdPmuBase|0|UINT32|0x00000008 + gExynosPkgTokenSpaceGuid.PcdGdbUartBase|0|UINT32|0x00000009 + gExynosPkgTokenSpaceGuid.PcdGpioPart1Base|0|UINT32|0x0000000A + gExynosPkgTokenSpaceGuid.PcdGpioPart2Base|0|UINT32|0x0000000B + gExynosPkgTokenSpaceGuid.PcdGpioPart3Base|0|UINT32|0x0000000C + gExynosPkgTokenSpaceGuid.PcdGpioPart4Base|0|UINT32|0x0000000D + gExynosPkgTokenSpaceGuid.PcdSdMmcBase|0|UINT32|0x0000000E + gExynosPkgTokenSpaceGuid.PcdSysBase|0|UINT32|0x0000000F + gExynosPkgTokenSpaceGuid.PcdFIMD1Base|0|UINT32|0x00000010 + gExynosPkgTokenSpaceGuid.PcdGICBase|0|UINT32|0x00000011 + gExynosPkgTokenSpaceGuid.PcdTZPCBase|0|UINT32|0x00000012 + gExynosPkgTokenSpaceGuid.PcdDSIM1Base|0|UINT32|0x00000013 + gExynosPkgTokenSpaceGuid.PcdSMC911XBase|0|UINT32|0x00000014 + gExynosPkgTokenSpaceGuid.PcdRtcBase|0|UINT32|0x00000015 + gExynosPkgTokenSpaceGuid.PcdExynos5250Evt1|FALSE|BOOLEAN|0x00000016 + gExynosPkgTokenSpaceGuid.PcdSdMmcCH0Base|0|UINT32|0x00000017 + gExynosPkgTokenSpaceGuid.PcdCryptoBase|0|UINT32|0x00000018 + + + # + # SMBIOS related + # + gExynosPkgTokenSpaceGuid.PcdProcessorInfoSockInfoStr|"Samsung Exynos5250"|VOID*|0x00000A00 + # Following can be changed by OEM's as it suits their products + gExynosPkgTokenSpaceGuid.PcdSystemMfrStr|"Samsung's OEM"|VOID*|0x00000A01 + gExynosPkgTokenSpaceGuid.PcdSystemProductNameStr|"Exynos5250 Product"|VOID*|0x00000A02 + gExynosPkgTokenSpaceGuid.PcdSystemProductFamilyStr|"Exynos5250 Product Family"|VOID*|0x00000A03 + + +# Samsung specific GUID = be26dd4f-9d02-413c-aa4f-dcd4aa334122 +[Protocols.common] diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/ExynosLib.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/ExynosLib.h new file mode 100644 index 000000000..8cd9fad2e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/ExynosLib.h @@ -0,0 +1,42 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EXYNOSLIB_H__ +#define __EXYNOSLIB_H__ + +/*=========================================================================== + MACRO DECLARATIONS +===========================================================================*/ +/** + gExynosPkgTokenSpaceGuid GUID definition. +*/ +#define EXYNOSPKG_TOKEN_SPACE_GUID \ + { 0x70b6655a, 0x7a03, 0x11e0, { 0xbe, 0x19, 0x00, 0x26, 0xb9, 0x73, 0x3e, 0x2c } } + +/*=========================================================================== + EXTERNAL VARIABLES +===========================================================================*/ +/** + External reference to the gExynosPkgTokenSpaceGuid GUID. +*/ +extern EFI_GUID gExynosPkgTokenSpaceGuid; + + +UINT32 +EFIAPI +GpioBase ( + IN UINTN Port + ); + +#endif // __EXYNOSLIB_H__ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/ExynosTimerLib.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/ExynosTimerLib.h new file mode 100644 index 000000000..783dd6d5f --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/ExynosTimerLib.h @@ -0,0 +1,56 @@ +/** @file +* +* Copyright (c) 2012, Samsung Electronics Co. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + + +#ifndef _EXYNOSTIMERLIB_H__ +#define _EXYNOSTIMERLIB_H__ + +#define PWM_TCFG0_OFFSET (0x0000) +#define PWM_TCFG1_OFFSET (0x0004) +#define PWM_TCON_OFFSET (0x0008) +#define PWM_TCNTB0_OFFSET (0x000C) +#define PWM_TCMPB0_OFFSET (0x0010) +#define PWM_TCNTO0_OFFSET (0x0014) +#define PWM_TCNTB1_OFFSET (0x0018) +#define PWM_TCMPB1_OFFSET (0x001C) +#define PWM_TCNTO1_OFFSET (0x0020) +#define PWM_TCNTB2_OFFSET (0x0024) +#define PWM_TCMPB2_OFFSET (0x0028) +#define PWM_TCNTO2_OFFSET (0x002C) +#define PWM_TCNTB3_OFFSET (0x0030) +#define PWM_TCMPB3_OFFSET (0x0034) +#define PWM_TCNTO3_OFFSET (0x0038) +#define PWM_TINT_CSTAT_OFFSET (0x0044) + +// Exynos4210 Timer constants +#define Exynos4210_TIMER_LOAD_REG 0x00 +#define Exynos4210_TIMER_CURRENT_REG 0x04 +#define Exynos4210_TIMER_CONTROL_REG 0x08 +#define Exynos4210_TIMER_INT_CLR_REG 0x0C +#define Exynos4210_TIMER_RAW_INT_STS_REG 0x10 +#define Exynos4210_TIMER_MSK_INT_STS_REG 0x14 +#define Exynos4210_TIMER_BG_LOAD_REG 0x18 + +// Timer control register bit definitions +#define Exynos4210_TIMER_CTRL_ONESHOT BIT0 +#define Exynos4210_TIMER_CTRL_32BIT BIT1 +#define Exynos4210_TIMER_CTRL_PRESCALE_MASK (BIT3|BIT2) +#define Exynos4210_PRESCALE_DIV_1 0 +#define Exynos4210_PRESCALE_DIV_16 BIT2 +#define Exynos4210_PRESCALE_DIV_256 BIT3 +#define Exynos4210_TIMER_CTRL_INT_ENABLE BIT5 +#define Exynos4210_TIMER_CTRL_PERIODIC BIT6 +#define Exynos4210_TIMER_CTRL_ENABLE BIT7 + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/MpParkLib.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/MpParkLib.h new file mode 100644 index 000000000..688051b42 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/MpParkLib.h @@ -0,0 +1,51 @@ +/** @file + Template for Timer Architecture Protocol driver of the ARM flavor + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef __MPPARKLIB_H_ +#define __MPPARKLIB_H_ + +/*=========================================================================== + + INCLUDE FILES FOR MODULE + +===========================================================================*/ + +/*=========================================================================== + + Defines and Structs + +===========================================================================*/ +extern UINT32 MpParkGPT0CntAddr; +extern UINT32 MpParkGPT0MatchAddr; +extern UINT32 MpParkGPT0EnableAddr; +extern UINT32 MpParkMPMCountAddr; + +/*=========================================================================== + + Public Functions + +===========================================================================*/ +void CPU1_Start(void); + + +/*=========================================================================== + + Private Functions + +===========================================================================*/ + +#endif // __MPPARKLIB_H_ + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/com_dtypes.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/com_dtypes.h new file mode 100644 index 000000000..02e113c31 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Library/com_dtypes.h @@ -0,0 +1,186 @@ +#ifndef COM_DTYPES_H +#define COM_DTYPES_H +/** @file + Template for Timer Architecture Protocol driver of the ARM flavor + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +/*=========================================================================== + + Data Declarations + +===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* For NT apps we want to use the Win32 definitions and/or those +** supplied by the Win32 compiler for things like NULL, MAX, MIN +** abs, labs, etc. +*/ +#ifdef T_WINNT + #ifndef WIN32 + #define WIN32 + #endif + #include <stdlib.h> +#endif + +/* ------------------------------------------------------------------------ +** Constants +** ------------------------------------------------------------------------ */ + +#ifdef TRUE +#undef TRUE +#endif + +#ifdef FALSE +#undef FALSE +#endif + +#define TRUE 1 /* Boolean true value. */ +#define FALSE 0 /* Boolean false value. */ + +#define ON 1 /* On value. */ +#define OFF 0 /* Off value. */ + +#ifndef NULL + #define NULL 0 +#endif + +/* ----------------------------------------------------------------------- +** Standard Types +** ----------------------------------------------------------------------- */ + +/* The following definitions are the same accross platforms. This first +** group are the sanctioned types. +*/ +#ifndef _ARM_ASM_ +#ifndef _BOOLEAN_DEFINED +typedef unsigned char boolean; /* Boolean value type. */ +#define _BOOLEAN_DEFINED +#endif + + +#if defined(DALSTDDEF_H) /* guards against a known re-definer */ +#define _BOOLEAN_DEFINED +#define _UINT32_DEFINED +#define _UINT16_DEFINED +#define _UINT8_DEFINED +#define _INT32_DEFINED +#define _INT16_DEFINED +#define _INT8_DEFINED +#define _UINT64_DEFINED +#define _INT64_DEFINED +#define _BYTE_DEFINED +#endif /* #if !defined(DALSTDDEF_H) */ + +#ifndef _UINT32_DEFINED +typedef unsigned long int uint32; /* Unsigned 32 bit value */ +#define _UINT32_DEFINED +#endif + +#ifndef _UINT16_DEFINED +typedef unsigned short uint16; /* Unsigned 16 bit value */ +#define _UINT16_DEFINED +#endif + +#ifndef _UINT8_DEFINED +typedef unsigned char uint8; /* Unsigned 8 bit value */ +#define _UINT8_DEFINED +#endif + +#ifndef _INT32_DEFINED +typedef signed long int int32; /* Signed 32 bit value */ +#define _INT32_DEFINED +#endif + +#ifndef _INT16_DEFINED +typedef signed short int16; /* Signed 16 bit value */ +#define _INT16_DEFINED +#endif + +#ifndef _INT8_DEFINED +typedef signed char int8; /* Signed 8 bit value */ +#define _INT8_DEFINED +#endif + +/* This group are the deprecated types. Their use should be +** discontinued and new code should use the types above +*/ +#ifndef _BYTE_DEFINED +typedef unsigned char byte; /* Unsigned 8 bit value type. */ +#define _BYTE_DEFINED +#endif + +typedef unsigned short word; /* Unsinged 16 bit value type. */ +typedef unsigned long dword; /* Unsigned 32 bit value type. */ + +typedef unsigned char uint1; /* Unsigned 8 bit value type. */ +typedef unsigned short uint2; /* Unsigned 16 bit value type. */ +typedef unsigned long uint4; /* Unsigned 32 bit value type. */ + +typedef signed char int1; /* Signed 8 bit value type. */ +typedef signed short int2; /* Signed 16 bit value type. */ +typedef long int int4; /* Signed 32 bit value type. */ + +typedef signed long sint31; /* Signed 32 bit value */ +typedef signed short sint15; /* Signed 16 bit value */ +typedef signed char sint7; /* Signed 8 bit value */ + +typedef uint16 UWord16 ; +typedef uint32 UWord32 ; +typedef int32 Word32 ; +typedef int16 Word16 ; +typedef uint8 UWord8 ; +typedef int8 Word8 ; +typedef int32 Vect32 ; + +#if (! defined T_WINNT) && (! defined __GNUC__) + /* Non WinNT Targets */ + #ifndef _INT64_DEFINED + typedef long long int64; /* Signed 64 bit value */ + #define _INT64_DEFINED + #endif + #ifndef _UINT64_DEFINED + typedef unsigned long long uint64; /* Unsigned 64 bit value */ + #define _UINT64_DEFINED + #endif +#else /* T_WINNT || TARGET_OS_SOLARIS || __GNUC__ */ + /* WINNT or SOLARIS based targets */ + #if (defined __GNUC__) + #ifndef _INT64_DEFINED + typedef long long int64; + #define _INT64_DEFINED + #endif + #ifndef _UINT64_DEFINED + typedef unsigned long long uint64; + #define _UINT64_DEFINED + #endif + #else + typedef __int64 int64; /* Signed 64 bit value */ + #ifndef _UINT64_DEFINED + typedef unsigned __int64 uint64; /* Unsigned 64 bit value */ + #define _UINT64_DEFINED + #endif + #endif +#endif /* T_WINNT */ + +#endif /* _ARM_ASM_ */ + +#ifdef __cplusplus +} +#endif + +#endif /* COM_DTYPES_H */ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/ArmPlatform.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/ArmPlatform.h new file mode 100755 index 000000000..4d5f7d86f --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/ArmPlatform.h @@ -0,0 +1,692 @@ +/** @file +* Header defining RealView EB constants (Base addresses, sizes, flags) +* +* Copyright (c) 2012, Samsung Electronics Co. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __ARMPLATFORM_H__ +#define __ARMPLATFORM_H__ + +/******************************************* +// Platform Memory Map +*******************************************/ + +/******************************************* +// Motherboard peripherals +*******************************************/ +//PMU DOMAIN offsets +#define SWRESET_OFFSET (0x400) +#define PMU_DISP1_CONFIGURATION_OFFSET (0x40A0) +#define PMU_DISP1_STATUS_OFFSET (0x40A4) + +#define LOCAL_PWR_ENABLE (0x07) + +#define PMU_MIPI_PHY1_CONTROL_OFFSET (0x0714) + +// SYSTRCL Register +#define ARM_EB_SYSCTRL 0x10001000 + +#define PL011_CONSOLE_UART_SPEED 115200 + +// IRAM & RAM Base Address +#define CONFIG_PHY_SDRAM_BASE (0x40000000) +#define CONFIG_PHY_IRAM_BASE (0x02020000) +#define CONFIG_PHY_UEFI_BASE (CONFIG_PHY_SDRAM_BASE) +#define CONFIG_SECURE_CONTEXT_BASE (CONFIG_PHY_IRAM_BASE + 0x4c00) +#define CONFIG_PHY_TZSW_BASE (CONFIG_PHY_IRAM_BASE + 0x8000) +#define CONFIG_PHY_IRAM_NS_BASE (CONFIG_PHY_IRAM_BASE + 0x2F000) +#define CONFIG_IMAGE_INFO_BASE (CONFIG_PHY_IRAM_NS_BASE + 0x11000) + +// Exynos5250 DMC Base Address : Not used it. +#define Exynos5250_DMC_DELAY 0x3000 +#define Exynos5250_DMC_0_BASE 0x10C00000 +#define Exynos5250_DMC_1_BASE 0x10C10000 + + +// Exynos5250 DMC Base Address +#define DMC_CTRL_BASE 0x10DD0000 + +#define DMC_CONCONTROL 0x00 +#define DMC_MEMCONTROL 0x04 +#define DMC_MEMCONFIG0 0x08 +#define DMC_MEMCONFIG1 0x0C +#define DMC_DIRECTCMD 0x10 +#define DMC_PRECHCONFIG 0x14 +#define DMC_PHYCONTROL0 0x18 +#define DMC_PWRDNCONFIG 0x28 +#define DMC_TIMINGPZQ 0x2C +#define DMC_TIMINGAREF 0x30 +#define DMC_TIMINGROW 0x34 +#define DMC_TIMINGDATA 0x38 +#define DMC_TIMINGPOWER 0x3C +#define DMC_PHYSTATUS 0x40 +#define DMC_CHIPSTATUS_CH0 0x48 +#define DMC_CHIPSTATUS_CH1 0x4C +#define DMC_MRSTATUS 0x54 +#define DMC_QOSCONTROL0 0x60 +#define DMC_QOSCONTROL1 0x68 +#define DMC_QOSCONTROL2 0x70 +#define DMC_QOSCONTROL3 0x78 +#define DMC_QOSCONTROL4 0x80 +#define DMC_QOSCONTROL5 0x88 +#define DMC_QOSCONTROL6 0x90 +#define DMC_QOSCONTROL7 0x98 +#define DMC_QOSCONTROL8 0xA0 +#define DMC_QOSCONTROL9 0xA8 +#define DMC_QOSCONTROL10 0xB0 +#define DMC_QOSCONTROL11 0xB8 +#define DMC_QOSCONTROL12 0xC0 +#define DMC_QOSCONTROL13 0xC8 +#define DMC_QOSCONTROL14 0xD0 +#define DMC_QOSCONTROL15 0xD8 +#define DMC_IVCONTROL 0xF0 +#define DMC_WRTRA_CONFIG 0x00F4 +#define DMC_RDLVL_CONFIG 0x00F8 +#define DMC_BRBRSVCONTROL 0x0100 +#define DMC_BRBRSVCONFIG 0x0104 +#define DMC_BRBQOSCONFIG 0x0108 +#define DMC_MEMBASECONFIG0 0x010C +#define DMC_MEMBASECONFIG1 0x0110 +#define DMC_WRLVL_CONFIG 0x0120 +#define DMC_PMNC_PPC 0xE000 +#define DMC_CNTENS_PPC 0xE010 +#define DMC_CNTENC_PPC 0xE020 +#define DMC_INTENS_PPC 0xE030 +#define DMC_INTENC_PPC 0xE040 +#define DMC_FLAG_PPC 0xE050 +#define DMC_CCNT_PPC 0xE100 +#define DMC_PMCNT0_PPC 0xE110 +#define DMC_PMCNT1_PPC 0xE120 +#define DMC_PMCNT2_PPC 0xE130 +#define DMC_PMCNT3_PPC 0xE140 + +/* PHY Control Register */ +#define PHY0_CTRL_BASE 0x10C00000 +#define PHY1_CTRL_BASE 0x10C10000 + +#define DMC_PHY_CON0 0x00 +#define DMC_PHY_CON1 0x04 +#define DMC_PHY_CON2 0x08 +#define DMC_PHY_CON3 0x0C +#define DMC_PHY_CON4 0x10 +#define DMC_PHY_CON6 0x18 +#define DMC_PHY_CON8 0x20 +#define DMC_PHY_CON10 0x28 +#define DMC_PHY_CON11 0x2C +#define DMC_PHY_CON12 0x30 +#define DMC_PHY_CON13 0x34 +#define DMC_PHY_CON14 0x38 +#define DMC_PHY_CON15 0x3C +#define DMC_PHY_CON16 0x40 +#define DMC_PHY_CON17 0x48 +#define DMC_PHY_CON18 0x4C +#define DMC_PHY_CON19 0x50 +#define DMC_PHY_CON20 0x54 +#define DMC_PHY_CON21 0x58 +#define DMC_PHY_CON22 0x5C +#define DMC_PHY_CON23 0x60 +#define DMC_PHY_CON24 0x64 +#define DMC_PHY_CON25 0x68 +#define DMC_PHY_CON26 0x6C +#define DMC_PHY_CON27 0x70 +#define DMC_PHY_CON28 0x74 +#define DMC_PHY_CON29 0x78 +#define DMC_PHY_CON30 0x7C +#define DMC_PHY_CON31 0x80 +#define DMC_PHY_CON32 0x84 +#define DMC_PHY_CON33 0x88 +#define DMC_PHY_CON34 0x8C +#define DMC_PHY_CON35 0x90 +#define DMC_PHY_CON36 0x94 +#define DMC_PHY_CON37 0x98 +#define DMC_PHY_CON38 0x9C +#define DMC_PHY_CON39 0xA0 +#define DMC_PHY_CON40 0xA4 +#define DMC_PHY_CON41 0xA8 +#define DMC_PHY_CON42 0xAC + + + + + + +// Exynos5250 UART Register +#define Exynos5250_UART_BASE 0x12C10000 + +#define ULCON_OFFSET 0x00 +#define UCON_OFFSET 0x04 +#define UFCON_OFFSET 0x08 +#define UMCON_OFFSET 0x0C +#define UTRSTAT_OFFSET 0x10 +#define UERSTAT_OFFSET 0x14 +#define UFSTAT_OFFSET 0x18 +#define UMSTAT_OFFSET 0x1C +#define UTXH_OFFSET 0x20 +#define URXH_OFFSET 0x24 +#define UBRDIV_OFFSET 0x28 +#define UDIVSLOT_OFFSET 0x2C +#define UINTP_OFFSET 0x30 +#define UINTSP_OFFSET 0x34 +#define UINTM_OFFSET 0x38 + + +#define UARTLCR_H ULCON_OFFSET +#define UARTECR UFCON_OFFSET +#define UARTCR UCON_OFFSET +#define UARTIBRD UBRDIV_OFFSET +#define UARTFBRD UDIVSLOT_OFFSET + +#define UART_TX_EMPTY_FLAG_MASK (0x02) +#define UART_RX_EMPTY_FLAG_MASK (0x01) +// Exynos5250 TZPC Register +#define Exynos5250_TZPC0_BASE 0x10100000 +#define Exynos5250_TZPC1_BASE 0x10110000 +#define Exynos5250_TZPC2_BASE 0x10120000 +#define Exynos5250_TZPC3_BASE 0x10130000 +#define Exynos5250_TZPC4_BASE 0x10140000 +#define Exynos5250_TZPC5_BASE 0x10150000 +#define Exynos5250_TZPC6_BASE 0x10160000 +#define Exynos5250_TZPC7_BASE 0x10170000 +#define Exynos5250_TZPC8_BASE 0x10180000 +#define Exynos5250_TZPC9_BASE 0x10190000 + + +#define TZPC0_OFFSET 0x00000 +#define TZPC1_OFFSET 0x10000 +#define TZPC2_OFFSET 0x20000 +#define TZPC3_OFFSET 0x30000 +#define TZPC4_OFFSET 0x40000 +#define TZPC5_OFFSET 0x50000 +#define TZPC6_OFFSET 0x60000 +#define TZPC7_OFFSET 0x70000 +#define TZPC8_OFFSET 0x80000 +#define TZPC9_OFFSET 0x90000 + +#define TZPC_DECPROT0SET_OFFSET 0x804 +#define TZPC_DECPROT1SET_OFFSET 0x810 +#define TZPC_DECPROT2SET_OFFSET 0x81C +#define TZPC_DECPROT3SET_OFFSET 0x828 + + +// Exynos5250 CMU Base Address +#define Exynos5250_CMU_DELAY 0x2000 +#define Exynos5250_CMU_BASE 0x10010000 +#define Exynos5250_CMU_DIV_DMC0 0x10500 + +#define APLL_AFC_ENB 0x1 +#define APLL_AFC 0xC + +/* MPLL_CON1 */ +#define MPLL_AFC_ENB 0x0 +#if defined(CONFIG_CLK_800_330_165) || defined(CONFIG_CLK_1000_330_165) +#define MPLL_AFC 0xD +#elif defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200) +#define MPLL_AFC 0x1C +#endif + +#define EPLL_PDIV 0x3 +#define EPLL_K 0x0 +#define VPLL_PDIV 0x3 +#define VPLL_SDIV 0x2 + +#define VPLL_SSCG_EN 0x0 +#define VPLL_SEL_PF 0x0 +#define VPLL_MRR 0x11 +#define VPLL_MFR 0x0 +#define VPLL_K 0x400 +/********************************************************/ + +/* Set PLL */ +#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv) + +/* CLK_SRC_CPU */ +/* 0 = MOUTAPLL, 1 = SCLKMPLL */ +#define MUX_HPM_SEL_MOUTAPLL 0 +#define MUX_HPM_SEL_SCLKMPLL 1 +#define MUX_CORE_SEL_MOUTAPLL 0 +#define MUX_CORE_SEL_SCLKMPLL 1 + +/* 0 = FILPLL, 1 = MOUT */ +#define MUX_MPLL_SEL_FILPLL 0 +#define MUX_MPLL_SEL_MOUTMPLLFOUT 1 + +#define MUX_APLL_SEL_FILPLL 0 +#define MUX_APLL_SEL_MOUTMPLLFOUT 1 + +#define CLK_SRC_CPU_VAL_FINPLL ((MUX_HPM_SEL_MOUTAPLL << 20) \ + | (MUX_CORE_SEL_MOUTAPLL <<16) \ + | (MUX_MPLL_SEL_FILPLL << 8) \ + | (MUX_APLL_SEL_FILPLL <<0)) + +#define CLK_SRC_CPU_VAL_MOUTMPLLFOUT ((MUX_HPM_SEL_MOUTAPLL << 20) \ + | (MUX_CORE_SEL_MOUTAPLL <<16) \ + | (MUX_MPLL_SEL_MOUTMPLLFOUT << 8) \ + | (MUX_APLL_SEL_MOUTMPLLFOUT <<0)) + +/* CLK_DIV_CPU0 */ +#define APLL_RATIO 0x1 +#define PCLK_DBG_RATIO 0x1 +#define ATB_RATIO 0x3 +#define COREM1_RATIO 0x7 +#define COREM0_RATIO 0x3 +#define CORE_RATIO 0x0 + +/* CLK_DIV_CPU1 */ +#define HPM_RATIO 0x0 +#define COPY_RATIO 0x3 +#define CLK_DIV_CPU1_VAL ((HPM_RATIO << 4) | (COPY_RATIO)) + +/* CLK_SRC_DMC */ +#define MUX_PWI_SEL 0x0 +#define MUX_CORE_TIMERS_SEL 0x0 +#define MUX_DPHY_SEL 0x0 +#define MUX_DMC_BUS_SEL 0x0 +#define CLK_SRC_DMC_VAL ((MUX_PWI_SEL << 16) \ + | (MUX_CORE_TIMERS_SEL << 12) \ + | (MUX_DPHY_SEL << 8) \ + | (MUX_DMC_BUS_SEL << 4)) + +/* CLK_DIV_DMC0 */ +#if defined(CONFIG_CLK_1000_200_200) +#define CORE_TIMERS_RATIO 0x1 +#define COPY2_RATIO 0x3 +#define DMCP_RATIO 0x1 +#define DMCD_RATIO 0x0 +#define DMC_RATIO 0x3 +#define DPHY_RATIO 0x1 +#define ACP_PCLK_RATIO 0x1 +#define ACP_RATIO 0x3 +#else +#define CORE_TIMERS_RATIO 0x1 +#define COPY2_RATIO 0x3 +#define DMCP_RATIO 0x1 +#define DMCD_RATIO 0x1 +#define DMC_RATIO 0x1 +#define DPHY_RATIO 0x1 +#define ACP_PCLK_RATIO 0x1 +#endif +#define CLK_DIV_DMC0_VAL ((CORE_TIMERS_RATIO << 28) \ + | (COPY2_RATIO << 24) \ + | (DMCP_RATIO << 20) \ + | (DMCD_RATIO << 16) \ + | (DMC_RATIO << 12) \ + | (DPHY_RATIO << 8) \ + | (ACP_PCLK_RATIO << 4) \ + | (ACP_RATIO)) + +/* CLK_DIV_DMC1 */ +#define DPM_RATIO 0x1 +#define DVSEM_RATIO 0x1 +#define PWI_RATIO 0x1 +#define CLK_DIV_DMC1_VAL ((DPM_RATIO << 24) \ + | (DVSEM_RATIO << 16) \ + | (PWI_RATIO << 8)) + +/* CLK_SRC_TOP0 */ +#define MUX_ONENAND_SEL 0x0 /* 0 = DOUT133, 1 = DOUT166 */ +#define MUX_ACLK_133_SEL 0x0 /* 0 = SCLKMPLL, 1 = SCLKAPLL */ +#define MUX_ACLK_160_SEL 0x0 +#define MUX_ACLK_100_SEL 0x0 +#define MUX_ACLK_200_SEL 0x0 +#define MUX_VPLL_SEL 0x0 +#define MUX_EPLL_SEL 0x0 + +/* CLK_SRC_TOP1 */ +#define VPLLSRC_SEL 0x0 /* 0 = FINPLL, 1 = SCLKHDMI27M */ + +/* CLK_DIV_TOP */ +#define ONENAND_RATIO 0x0 +#define ACLK_160_RATIO 0x4 +#define ACLK_100_RATIO 0x7 +#define ACLK_200_RATIO 0x3 +#define CLK_DIV_TOP_VAL ((ONENAND_RATIO << 16) \ + | (ACLK_133_RATIO << 12) \ + | (ACLK_160_RATIO << 8) \ + | (ACLK_100_RATIO << 4) \ + | (ACLK_200_RATIO)) + +/* CLK_SRC_LEFTBUS */ +#define MUX_GDL_SEL 0x0 +#define CLK_SRC_LEFTBUS_VAL (MUX_GDL_SEL) + +/* CLK_DIV_LEFRBUS */ +#define GPL_RATIO 0x1 +#define GDL_RATIO 0x3 +#define CLK_DIV_LEFRBUS_VAL ((GPL_RATIO << 4) \ + | (GDL_RATIO)) + +/* CLK_SRC_RIGHTBUS */ +#define MUX_GDR_SEL 0x0 +#define CLK_SRC_RIGHTBUS_VAL (MUX_GDR_SEL) + +/* CLK_DIV_RIGHTBUS */ +#define GPR_RATIO 0x1 +#define GDR_RATIO 0x3 +#define CLK_DIV_RIGHTBUS_VAL ((GPR_RATIO << 4) \ + | (GDR_RATIO)) + +#define PLL_LOCKTIME 0x1C20 + +/* CLK_SRC_PERIL0 */ +#define PWM_SEL 0 +#define UART5_SEL 6 +#define UART4_SEL 6 +#define UART3_SEL 6 +#define UART2_SEL 6 +#define UART1_SEL 6 +#define UART0_SEL 6 +#define CLK_SRC_PERIL0_VAL ((PWM_SEL << 24)\ + | (UART5_SEL << 20) \ + | (UART4_SEL << 16) \ + | (UART3_SEL << 12) \ + | (UART2_SEL<< 8) \ + | (UART1_SEL << 4) \ + | (UART0_SEL)) + +/* CLK_DIV_PERIL0 */ +#if defined(CONFIG_CLK_800_330_165) || defined(CONFIG_CLK_1000_330_165) +#define UART5_RATIO 7 +#define UART4_RATIO 7 +#define UART3_RATIO 7 +#define UART2_RATIO 7 +#define UART1_RATIO 7 +#define UART0_RATIO 7 +#elif defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200) +#define UART5_RATIO 8 +#define UART4_RATIO 8 +#define UART3_RATIO 8 +#define UART2_RATIO 8 +#define UART1_RATIO 8 +#define UART0_RATIO 8 +#endif +#define CLK_DIV_PERIL0_VAL ((UART5_RATIO << 20) \ + | (UART4_RATIO << 16) \ + | (UART3_RATIO << 12) \ + | (UART2_RATIO << 8) \ + | (UART1_RATIO << 4) \ + | (UART0_RATIO)) + +#define MPLL_DEC (MPLL_MDIV * MPLL_MDIV / (MPLL_PDIV * 2^(MPLL_SDIV-1))) + +#if defined(CONFIG_CLK_800_330_165) || defined(CONFIG_CLK_1000_330_165) +#define UART_UBRDIV_VAL 0x2B/* (SCLK_UART/(115200*16) -1) */ +#define UART_UDIVSLOT_VAL 0xC /*((((SCLK_UART*10/(115200*16) -10))%10)*16/10)*/ +#elif defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200) +#define UART_UBRDIV_VAL 0x2F /* (SCLK_UART/(115200*16) -1) */ +#define UART_UDIVSLOT_VAL 0x3 /*((((SCLK_UART*10/(115200*16) -10))%10)*16/10)*/ +#endif + +#define UART_115200_IDIV UART_UBRDIV_VAL +#define UART_115200_FDIV UART_UDIVSLOT_VAL + +#define UART_38400_IDIV UART_UBRDIV_VAL +#define UART_38400_FDIV UART_UDIVSLOT_VAL + +#define UART_19200_IDIV UART_UBRDIV_VAL +#define UART_19200_FDIV UART_UDIVSLOT_VAL + +#define UART_LCON_VAL 0x03 +#define UART_ECR_VAL 0x111 +#define UART_CR_VAL 0x3C5 + +// System Configuration Controller register Base addresses +#define SYS_DISP1BLK_CFG_OFFSET (0x0214) +#define FIMDBYPASS_DISP1 (0x01 << 15) + +//FIMD register offsets +#define VIDCON0_OFFSET (0x00) +#define VIDCON1_OFFSET (0x20004)/* Video control 1 */ +#define VIDCON2_OFFSET (0x0008) /* Video control 2 */ +#define VIDTCON0_OFFSET (0x20010) /* Video time control 0 */ +#define VIDTCON1_OFFSET (0x20014) /* Video time control 1 */ +#define VIDTCON2_OFFSET (0x20018) /* Video time control 2 */ +#define SHADOWCON_OFFSET (0x0034) /* Window Shadow control */ +#define WINCON_OFFSET(x) (0x0020 + (x * 0x04)) +#define VIDOSD_A_OFFSET(x) (0x0040 + (x * 0x10)) +#define VIDOSD_B_OFFSET(x) (0x0044 + (x * 0x10)) +#define VIDOSD_C_OFFSET(x) (0x0048 + (x * 0x10)) +#define VIDADDR_START0_OFFSET(x)(0x00A0 + (x * 0x08)) +#define VIDADDR_END0_OFFSET(x) (0x00D0 + (x * 0x08)) +#define VIDADDR_SIZE_OFFSET(x) (0x0100 + (x * 0x04)) + +// MIPI-DSIM register offsets +#define DSIM_STATUS (0x00) +#define DSIM_SWRST (0x04) +#define DSIM_CLKCTRL (0x08) +#define DSIM_TIMEOUT (0x0C) +#define DSIM_CONFIG (0x10) +#define DSIM_ESCMODE (0x14) +#define DSIM_MDRESOL (0x18) +#define DSIM_MVPORCH (0x1C) +#define DSIM_MHPORCH (0x20) +#define DSIM_MSYNC (0x24) +#define DSIM_SDRESOL (0x28) +#define DSIM_INTSRC (0x2C) +#define DSIM_INTMSK (0x30) +#define DSIM_PKTHDR (0x34) +#define DSIM_PAYLOAD (0x38) +#define DSIM_RXFIFO (0x3C) +#define DSIM_FIFOTHLD (0x40) +#define DSIM_FIFOCTRL (0x44) +#define DSIM_MEMACCHR (0x48) +#define DSIM_PLLCTRL (0x4C) +#define DSIM_PLLTMR (0x50) +#define DSIM_PHYACCHR (0x54) +#define DSIM_PHYACCHR1 (0x58) + +// RTC register offset +#define EXYNOS_RTCREG(x) (x) +#define EXYNOS_INTP EXYNOS_RTCREG(0x30) +#define EXYNOS_INTP_ALM (1 << 1) +#define EXYNOS_INTP_TIC (1 << 0) + +#define EXYNOS_RTCCON EXYNOS_RTCREG(0x40) +#define EXYNOS_RTCCON_RTCEN (1<<0) +#define EXYNOS_RTCCON_CLKSEL (1<<1) +#define EXYNOS_RTCCON_CNTSEL (1<<2) +#define EXYNOS_RTCCON_CLKRST (1<<3) +#define EXYNOS_RTCCON_TICEN (1<<8) + +#define EXYNOS_RTCCON_TICMSK (0xF<<7) +#define EXYNOS_RTCCON_TICSHT (7) + +#define EXYNOS_TICNT EXYNOS_RTCREG(0x44) +#define EXYNOS_TICNT_ENABLE (1<<7) + +#define EXYNOS_RTCALM EXYNOS_RTCREG(0x50) +#define EXYNOS_RTCALM_ALMEN (1<<6) +#define EXYNOS_RTCALM_YEAREN (1<<5) +#define EXYNOS_RTCALM_MONEN (1<<4) +#define EXYNOS_RTCALM_DAYEN (1<<3) +#define EXYNOS_RTCALM_HOUREN (1<<2) +#define EXYNOS_RTCALM_MINEN (1<<1) +#define EXYNOS_RTCALM_SECEN (1<<0) + +#define EXYNOS_RTCALM_ALL \ + EXYNOS_RTCALM_ALMEN | EXYNOS_RTCALM_YEAREN | EXYNOS_RTCALM_MONEN |\ + EXYNOS_RTCALM_DAYEN | EXYNOS_RTCALM_HOUREN | EXYNOS_RTCALM_MINEN |\ + EXYNOS_RTCALM_SECEN + + +#define EXYNOS_ALMSEC EXYNOS_RTCREG(0x54) +#define EXYNOS_ALMMIN EXYNOS_RTCREG(0x58) +#define EXYNOS_ALMHOUR EXYNOS_RTCREG(0x5c) + +#define EXYNOS_ALMDAY EXYNOS_RTCREG(0x60) +#define EXYNOS_ALMMON EXYNOS_RTCREG(0x64) +#define EXYNOS_ALMYEAR EXYNOS_RTCREG(0x68) + +//#define EXYNOS_RTCRST EXYNOS_RTCREG(0x6c) + +#define EXYNOS_BCDSEC EXYNOS_RTCREG(0x70) +#define EXYNOS_BCDMIN EXYNOS_RTCREG(0x74) +#define EXYNOS_BCDHOUR EXYNOS_RTCREG(0x78) +#define EXYNOS_BCDDAY EXYNOS_RTCREG(0x7c) +#define EXYNOS_BCDDAYWEEK EXYNOS_RTCREG(0x80) +#define EXYNOS_BCDMON EXYNOS_RTCREG(0x84) +#define EXYNOS_BCDYEAR EXYNOS_RTCREG(0x88) + +// Kimoon add RTC clock gate +#define CLK_GATE_IP_PERIR (0xC960) +#define CLK_RTC_OFFSET (0x1 << 15) +#define CLK_RTC_MASK (0x0 << 15) +#define CLK_RTC_UNMASK (0x1 << 15) + +//#define CLK_DIV_FSYS2 (CLK_BASE + 0xC548) +//#define CLK_DIV_FSYS3 (CLK_BASE + 0xC54C) + + +/******************************************* +* Interrupt Map +*******************************************/ + +// Timer Interrupts +#define Exynos5250_INT_NUM(x) ((x) + 32) + +#define PWM_TIMER0_INTERRUPT_NUM Exynos5250_INT_NUM(36) +#define PWM_TIMER1_INTERRUPT_NUM Exynos5250_INT_NUM(37) +#define PWM_TIMER2_INTERRUPT_NUM Exynos5250_INT_NUM(38) +#define PWM_TIMER3_INTERRUPT_NUM Exynos5250_INT_NUM(39) +#define PWM_TIMER4_INTERRUPT_NUM Exynos5250_INT_NUM(40) + +/******************************************* +* EFI Memory Map in Permanent Memory (DRAM) +*******************************************/ + +//gpio definitions as required by the Embedded gpio module +#define DISTANCE_BTWN_PORTS (0x20) + +#define GPIO_CON (0x00) +#define GPIO_DATAIN (0x04) +#define GPIO_PUD (0x08) +#define GPIO_DRV (0x0C) + +#define GPIO_DATAIN_MASK(x) (1UL << (x)) +#define GPIO_PUD_MASK(x) (3UL << (x*2)) +#define GPIO_DRV_MASK(x) (3UL << (x*2)) +#define GPIO_SFN_MASK(x) (15UL <<(x*4)) + +#define GPIO_SFN_EN(x) (2UL << (x*4)) +#define GPIO_OP_EN(x) (1UL << (x*4)) + +#define GPIO_PUD_DIS(x) (0UL << (x*2)) +#define GPIO_PDN_EN(x) (1UL << (x*2)) +#define GPIO_PUP_EN(x) (3UL << (x*2)) +#define GPIO_DATA_HIGH(x) (1UL << (x)) +#define GPIO_DATA_LOW(x) (0UL << (x)) + +#define GPIO_DRV_SET(strength,pin) (strength << (pin*2)) + +#define PIN0 (0x00) +#define PIN1 (0x01) +#define PIN2 (0x02) +#define PIN3 (0x03) +#define PIN4 (0x04) +#define PIN5 (0x05) +#define PIN6 (0x06) +#define PIN7 (0x07) + +// 0x1140_0000 +#define GPA0 (0x00) +#define GPA1 (0x01) +#define GPA2 (0x02) +#define GPB0 (0x03) +#define GPB1 (0x04) +#define GPB2 (0x05) +#define GPB3 (0x06) +#define GPC0 (0x07) +#define GPC1 (0x08) +#define GPC2 (0x09) +#define GPC3 (0x0A) +#define GPD0 (0x0B) +#define GPD1 (0x0C) +#define GPY0 (0x0D) +#define GPY1 (0x0E) +#define GPY2 (0x0F) +#define GPY3 (0x10) +#define GPY4 (0x11) +#define GPY5 (0x12) +#define GPY6 (0x13) +#define GPX0 (0x60) +#define GPX1 (0x61) +#define GPX2 (0x62) +#define GPX3 (0x63) + +// 0x1340_0000 +#define GPE0 (0x70) +#define GPE1 (0x71) +#define GPF0 (0x72) +#define GPF1 (0x73) +#define GPG0 (0x74) +#define GPG1 (0x75) +#define GPG2 (0x76) +#define GPH0 (0x77) +#define GPH1 (0x78) + +// 0x10D1_0000 +#define GPV0 (0x80) +#define GPV1 (0x81) +// ETC5PUD +#define GPV2 (0x83) +#define GPV3 (0x84) +// ETC8PUD +#define GPV4 (0x86) + +// 0x0386_0000 +#define GPZ (0x90) + +#define LCD_BACKLIGHT GPIO(GPB2,PIN0) +#define LCD_RESET GPIO(GPX1,PIN5) +#define LCD_POWER GPIO(GPX3,PIN0) + +/* SDHC GPIO Pin Configuration for GAIA */ +#define SD_2_EVT1_CLK GPIO(GPC3,PIN0) +#define SD_2_EVT1_CMD GPIO(GPC3,PIN1) +#define SD_2_EVT1_CDn GPIO(GPC3,PIN2) +#define SD_2_EVT1_DATA0 GPIO(GPC3,PIN3) +#define SD_2_EVT1_DATA1 GPIO(GPC3,PIN4) +#define SD_2_EVT1_DATA2 GPIO(GPC3,PIN5) +#define SD_2_EVT1_DATA3 GPIO(GPC3,PIN6) + +#define SD_2_CLK GPIO(GPC2,PIN0) +#define SD_2_CMD GPIO(GPC2,PIN1) +#define SD_2_CDn GPIO(GPC2,PIN2) +#define SD_2_DATA0 GPIO(GPC2,PIN3) +#define SD_2_DATA1 GPIO(GPC2,PIN4) +#define SD_2_DATA2 GPIO(GPC2,PIN5) +#define SD_2_DATA3 GPIO(GPC2,PIN6) +#define SD_2_DATA4 GPIO(GPC3,PIN3) +#define SD_2_DATA5 GPIO(GPC3,PIN4) +#define SD_2_DATA6 GPIO(GPC3,PIN5) +#define SD_2_DATA7 GPIO(GPC3,PIN6) + +/* USB 2.0 GPIO Pin Configuration for GAIA Evt1 */ +#define USB_2_EVT1 GPIO(GPX2,PIN6) + +/* SDHC CH0 GPIO Pin Configuration for GAIA */ +#define SD_0_CLK GPIO(GPC0,PIN0) +#define SD_0_CMD GPIO(GPC0,PIN1) +#define SD_0_CDn GPIO(GPC0,PIN2) +#define SD_0_DATA0 GPIO(GPC0,PIN3) +#define SD_0_DATA1 GPIO(GPC0,PIN4) +#define SD_0_DATA2 GPIO(GPC0,PIN5) +#define SD_0_DATA3 GPIO(GPC0,PIN6) +#define SD_0_DATA4 GPIO(GPC1,PIN0) +#define SD_0_DATA5 GPIO(GPC1,PIN1) +#define SD_0_DATA6 GPIO(GPC1,PIN2) +#define SD_0_DATA7 GPIO(GPC1,PIN3) + + +#define CLK_DIV_FSYS1_OFFSET 0x1054C +#define CLK_DIV_FSYS2_OFFSET 0x10550 + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Arndale5250.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Arndale5250.h new file mode 100644 index 000000000..0762b8aeb --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Arndale5250.h @@ -0,0 +1,337 @@ +/* + * (C) Copyright 2009 Samsung Electronics + * Minkyu Kang <mk7.kang@samsung.com> + * HeungJun Kim <riverful.kim@samsung.com> + * Inki Dae <inki.dae@samsung.com> + * + * Configuation settings for the SAMSUNG ARNDALE board. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * High Level Configuration Options + * (easy to change) + */ +#define CONFIG_ARMV7 1 /* This is an ARM V7 CPU core */ +#define CONFIG_SAMSUNG 1 /* in a SAMSUNG core */ +#define CONFIG_S5P 1 /* which is in a S5P Family */ +#define CONFIG_ARCH_EXYNOS 1 /* which is in a Exynos Family */ +#define CONFIG_ARCH_EXYNOS5 1 /* which is in a Exynos5 Family */ +#define CONFIG_CPU_EXYNOS5250 1 /* which is in a Exynos5250 */ +#define CONFIG_MACH_SMDK5250 1 /* which is in a ARNDALE */ +#define CONFIG_EVT1 1 /* EVT1 */ +//#define CONFIG_CORTEXA5_ENABLE 1 /* enable coretex-A5(IOP) Booting */ + +#define CONFIG_SECURE_BL1_ONLY +//#define CONFIG_SECURE_BOOT +#ifdef CONFIG_SECURE_BOOT +#define CONFIG_S5PC210S +#define CONFIG_SECURE_ROOTFS +#define CONFIG_SECURE_KERNEL_BASE 0xc0008000 +#define CONFIG_SECURE_KERNEL_SIZE 0x200000 +#define CONFIG_SECURE_ROOTFS_BASE 0xc1000000 +#define CONFIG_SECURE_ROOTFS_SIZE 0x5c2000 +#endif + +//#include <asm/arch/cpu.h> /* get chip and board defs */ + +#define CONFIG_CLK_ARM_1000_APLL_1000 + +#define MCLK_CDREX_533 1 +#define RD_LVL 1 + +/* (Memory Interleaving Size = 1 << IV_SIZE) */ +#define CONFIG_IV_SIZE 0x07 + +#define CONFIG_L2_OFF + +//#define CONFIG_ARCH_CPU_INIT + +#define CONFIG_DISPLAY_CPUINFO +//#define CONFIG_DISPLAY_BOARDINFO +#define BOARD_LATE_INIT + +/* input clock of PLL: ARNDALE has 24MHz input clock */ +#define CONFIG_SYS_CLK_FREQ 24000000 + +/* DRAM Base */ +#define CONFIG_SYS_SDRAM_BASE 0x40000000 + +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_CMDLINE_TAG +#define CONFIG_INITRD_TAG +#define CONFIG_CMDLINE_EDITING + +/* Power Management is enabled */ +//#define CONFIG_PM +//#define CONFIG_INVERSE_PMIC_I2C 1 +#define CONFIG_PM_VDD_ARM 1.1 +#define CONFIG_PM_VDD_INT 1.0 +#define CONFIG_PM_VDD_G3D 1.1 +#define CONFIG_PM_VDD_MIF 1.1 +#define CONFIG_PM_VDD_LDO14 1.8 + +/* + * Size of malloc() pool + * 1MB = 0x100000, 0x100000 = 1024 * 1024 + */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (1 << 20)) + /* initial data */ +/* + * select serial console configuration + */ +#define CONFIG_SERIAL1 1 +#define CONFIG_SERIAL_MULTI 1 + +#define CONFIG_USB_OHCI +#undef CONFIG_USB_STORAGE +//#define CONFIG_S3C_USBD +#define CONFIG_EXYNOS_USBD3 + +#define USBD_DOWN_ADDR 0xc0000000 + +/* allow to overwrite serial and ethaddr */ +#define CONFIG_ENV_OVERWRITE +#define CONFIG_BAUDRATE 115200 + +/*********************************************************** + * Command definition + ***********************************************************/ + +#define CONFIG_CMD_PING + +#define CONFIG_CMD_USB + +#define CONFIG_CMD_MOVINAND + +#undef CONFIG_CMD_FLASH +#undef CONFIG_CMD_IMLS +#undef CONFIG_CMD_NAND + +#define CONFIG_CMD_CACHE +#define CONFIG_CMD_REGINFO +#define CONFIG_CMD_MMC +#define CONFIG_CMD_MOVI +#define CONFIG_CMD_ELF +#define CONFIG_CMD_FAT +#define CONFIG_CMD_MTDPARTS +#define CONFIG_MTD_DEVICE + +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_FAT + +#define CONFIG_SYS_NAND_QUIET_TEST +#define CONFIG_SYS_ONENAND_QUIET_TEST + +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_S3C_HSMMC + +/* The macro for MMC channel 0 is defined by default and can't be undefined */ + +/* Notice for MSHC[Using of MMC CH4] */ +/* + * If you want MSHC at MMC CH4. + */ + +#define MMC_MAX_CHANNEL 5 + +#define USE_MMC2 +#define USE_MMC4 + +/* + * BOOTP options + */ +#define CONFIG_BOOTP_SUBNETMASK +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_HOSTNAME +#define CONFIG_BOOTP_BOOTPATH + +#define CONFIG_ETHADDR 00:40:5c:26:0a:5b +#define CONFIG_NETMASK 255.255.255.0 +#define CONFIG_IPADDR 192.168.0.20 +#define CONFIG_SERVERIP 192.168.0.10 +#define CONFIG_GATEWAYIP 192.168.0.1 + +#define CONFIG_BOOTDELAY 3 +/* Default boot commands for Android booting. */ +#define CONFIG_BOOTCOMMAND "movi read kernel 0 40008000;movi read rootfs 0 41000000 100000;bootm 40008000 41000000" +#define CONFIG_BOOTARGS "" + +#define CONFIG_BOOTCOMMAND2 \ + "mmc erase user 0 1072 1;" \ + "movi r f 1 40000000;emmc open 0;movi w z f 0 40000000;emmc close 0;" \ + "movi r u 1 40000000;emmc open 0;movi w z u 0 40000000;emmc close 0;" \ + "movi r k 1 40000000;movi w k 0 40000000;" \ + "movi r r 1 40000000 100000;movi w r 0 40000000 100000;" \ + "fdisk -c 0;" \ + "movi init 0;" \ + "fatformat mmc 0:1;" \ + "mmc read 1 48000000 20000 a0000;" \ + "fastboot flash system 48000000;" \ + "mmc read 1 48000000 c0000 a0000;" \ + "fastboot flash userdata 48000000;" \ + "mmc read 1 48000000 160000 a0000;" \ + "fastboot flash cache 48000000;" \ + "reset" + +/* + * Miscellaneous configurable options + */ +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */ +#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " +#define CONFIG_SYS_PROMPT "ARNDALE# " +#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ +#define CONFIG_SYS_PBSIZE 384 /* Print Buffer Size */ +#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE +/* memtest works on */ +#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x5e00000) + +#define CONFIG_SYS_HZ 1000 + +/* valid baudrates */ +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + +/*----------------------------------------------------------------------- + * Stack sizes + * + * The stack sizes are set up in start.S using the settings below + */ +#define CONFIG_STACKSIZE (256 << 10) /* 256 KiB */ + +#define CONFIG_NR_DRAM_BANKS 4 +#define SDRAM_BANK_SIZE 0x10000000 /* 256 MB */ +#define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE /* SDRAM Bank #1 */ +#define PHYS_SDRAM_1_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_2 (CONFIG_SYS_SDRAM_BASE + SDRAM_BANK_SIZE) /* SDRAM Bank #2 */ +#define PHYS_SDRAM_2_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_3 (CONFIG_SYS_SDRAM_BASE + 2 * SDRAM_BANK_SIZE) /* SDRAM Bank #3 */ +#define PHYS_SDRAM_3_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_4 (CONFIG_SYS_SDRAM_BASE + 3 * SDRAM_BANK_SIZE) /* SDRAM Bank #4 */ +#define PHYS_SDRAM_4_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_5 (CONFIG_SYS_SDRAM_BASE + 4 * SDRAM_BANK_SIZE) /* SDRAM Bank #5 */ +#define PHYS_SDRAM_5_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_6 (CONFIG_SYS_SDRAM_BASE + 5 * SDRAM_BANK_SIZE) /* SDRAM Bank #6 */ +#define PHYS_SDRAM_6_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_7 (CONFIG_SYS_SDRAM_BASE + 6 * SDRAM_BANK_SIZE) /* SDRAM Bank #7 */ +#define PHYS_SDRAM_7_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_8 (CONFIG_SYS_SDRAM_BASE + 7 * SDRAM_BANK_SIZE) /* SDRAM Bank #8 */ +#define PHYS_SDRAM_8_SIZE SDRAM_BANK_SIZE + +#define CONFIG_SYS_MONITOR_BASE 0x00000000 + +/*----------------------------------------------------------------------- + * FLASH and environment organization + */ +#define CONFIG_SYS_NO_FLASH 1 + +#define CONFIG_SYS_MONITOR_LEN (256 << 10) /* 256 KiB */ +#define CONFIG_IDENT_STRING " for ARNDALE" + +#define CONFIG_ENABLE_MMU + +#ifdef CONFIG_ENABLE_MMU +#define CONFIG_SYS_MAPPED_RAM_BASE 0xc0000000 +#define virt_to_phys(x) virt_to_phy_exynos5250(x) +#else +#define CONFIG_SYS_MAPPED_RAM_BASE CONFIG_SYS_SDRAM_BASE +#define virt_to_phys(x) (x) +#endif + +#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_MAPPED_RAM_BASE + 0x3e00000 +#define CONFIG_PHY_UBOOT_BASE CONFIG_SYS_SDRAM_BASE + 0x3e00000 + +/* + * Fast Boot +*/ +/* Fastboot variables */ +#define CFG_FASTBOOT_TRANSFER_BUFFER (0x48000000) +#define CFG_FASTBOOT_TRANSFER_BUFFER_SIZE (0x10000000) /* 256MB */ +#define CFG_FASTBOOT_ADDR_KERNEL (0x40008000) +#define CFG_FASTBOOT_ADDR_RAMDISK (0x40800000) +#define CFG_FASTBOOT_PAGESIZE (2048) // Page size of booting device +#define CFG_FASTBOOT_SDMMC_BLOCKSIZE (512) // Block size of sdmmc +#define CFG_PARTITION_START (0x4000000) + +/* Just one BSP type should be defined. */ +#if defined(CONFIG_CMD_MOVINAND) +#define CONFIG_FASTBOOT +#endif + +#if defined(CONFIG_CMD_MOVINAND) +#define CFG_FASTBOOT_SDMMCBSP +#endif + +/* + * machine type + */ + +#define MACH_TYPE 3774 /* ARNDALE machine ID */ + +#define CONFIG_ENV_OFFSET 0x0007C000 + +/*----------------------------------------------------------------------- + * Boot configuration + */ +#define BOOT_ONENAND 0x1 +#define BOOT_NAND 0x40000 +#define BOOT_MMCSD 0x3 +#define BOOT_NOR 0x4 +#define BOOT_SEC_DEV 0x5 +#define BOOT_EMMC 0x6 +#define BOOT_EMMC_4_4 0x7 + +#define CONFIG_ZIMAGE_BOOT + +#define CONFIG_ENV_IS_IN_AUTO 1 +#define CONFIG_ENV_SIZE 0x4000 + +#define CONFIG_DOS_PARTITION 1 + +//#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_LOAD_ADDR - 0x1000000) +#define CONFIG_SYS_INIT_SP_ADDR (0x43e00000 - 0x1000000) + +/* + * Ethernet Contoller driver + */ +#define CONFIG_CMD_NET 1 +#ifdef CONFIG_CMD_NET +#define CONFIG_NET_MULTI +#define CONFIG_SMC911X +#define CONFIG_SMC911X_BASE 0x5000000 +#define CONFIG_SMC911X_16_BIT +#endif /* CONFIG_CMD_NET */ + +/* GPIO */ +#define GPIO_BASE 0x11400000 + +#define CFG_PHY_UBOOT_BASE MEMORY_BASE_ADDRESS + 0x3e00000 +#define CFG_PHY_KERNEL_BASE MEMORY_BASE_ADDRESS + 0x8000 + +#define MEMORY_BASE_ADDRESS 0x40000000 + +#endif /* __CONFIG_H */ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Arndale5250_Val.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Arndale5250_Val.h new file mode 100755 index 000000000..d6cdd1d9d --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Arndale5250_Val.h @@ -0,0 +1,402 @@ +/* + * (C) Copyright 2012 Samsung Electronics Co. Ltd + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + */ + +#ifndef _VAL_ARNDALE5250_H +#define _VAL_ARNDALE5250_H + +#if defined(CONFIG_CLK_ARM_800_APLL_800) + +#define APLL_MDIV 0x64 +#define APLL_PDIV 0x3 +#define APLL_SDIV 0x0 + +#elif defined(CONFIG_CLK_ARM_1000_APLL_1000) + +#define APLL_MDIV 0x7D +#define APLL_PDIV 0x3 +#define APLL_SDIV 0x0 + +#elif defined(CONFIG_CLK_ARM_1200_APLL_1200) + +#define APLL_MDIV 0x96 +#define APLL_PDIV 0x3 +#define APLL_SDIV 0x0 + +#elif defined(CONFIG_CLK_ARM_1400_APLL_1400) + +#define APLL_MDIV 0xAF +#define APLL_PDIV 0x3 +#define APLL_SDIV 0x0 + +#elif defined(CONFIG_CLK_ARM_1700_APLL_1700) + +#define APLL_MDIV 0xAF +#define APLL_PDIV 0x3 +#define APLL_SDIV 0x0 +#endif + +#define MPLL_MDIV 0x64 +#define MPLL_PDIV 0x3 +#define MPLL_SDIV 0x0 + +#define CPLL_MDIV 0xDE +#define CPLL_PDIV 0x4 +#define CPLL_SDIV 0x2 + +#define GPLL_MDIV 0x215 +#define GPLL_PDIV 0xC +#define GPLL_SDIV 0x1 + +/* APLL_CON1 */ +#define APLL_CON1_VAL (0x00203800) + +/* MPLL_CON1 */ +#define MPLL_CON1_VAL (0x00203800) + +/* CPLL_CON1 */ +#define CPLL_CON1_VAL (0x00203800) + +/* GPLL_CON1 */ +#define GPLL_CON1_VAL (0x00203800) + +#define EPLL_MDIV 0x60 +#define EPLL_PDIV 0x3 +#define EPLL_SDIV 0x3 + +#define EPLL_CON1_VAL 0x00000000 +#define EPLL_CON2_VAL 0x00000080 + +#define VPLL_MDIV 0x96 +#define VPLL_PDIV 0x3 +#define VPLL_SDIV 0x2 + +/* VPLL_CON1, CON2 */ +#define VPLL_CON1_VAL 0x00000000 +#define VPLL_CON2_VAL 0x00000080 + +#define BPLL_MDIV 0x64 +#define BPLL_PDIV 0x3 +#define BPLL_SDIV 0x0 + +/* BPLL_CON1 */ +#define BPLL_CON1_VAL 0x00203800 + +/* Set PLL */ +#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv) + +#define APLL_CON0_VAL set_pll(APLL_MDIV, APLL_PDIV, APLL_SDIV) +#define MPLL_CON0_VAL set_pll(MPLL_MDIV, MPLL_PDIV, MPLL_SDIV) +#define CPLL_CON0_VAL set_pll(CPLL_MDIV, CPLL_PDIV, CPLL_SDIV) +#define GPLL_CON0_VAL set_pll(GPLL_MDIV, GPLL_PDIV, GPLL_SDIV) +#define EPLL_CON0_VAL set_pll(EPLL_MDIV, EPLL_PDIV, EPLL_SDIV) +#define VPLL_CON0_VAL set_pll(VPLL_MDIV, VPLL_PDIV, VPLL_SDIV) +#define BPLL_CON0_VAL set_pll(BPLL_MDIV, BPLL_PDIV, BPLL_SDIV) + +/* CLK_SRC_CPU */ +/* 0 = MOUTAPLL, 1 = SCLKMPLL */ +#define MUX_HPM_SEL 0 +#define MUX_CPU_SEL 0 +#define MUX_APLL_SEL 1 + +#define CLK_SRC_CPU_VAL ((MUX_HPM_SEL << 20) \ + | (MUX_CPU_SEL << 16) \ + | (MUX_APLL_SEL)) + +/* CLK_DIV_CPU0 */ +#if defined(CONFIG_CLK_ARM_600_APLL_600) +#define ARM2_RATIO 0x0 +#define APLL_RATIO 0x1 +#define PCLK_DBG_RATIO 0x1 +#define ATB_RATIO 0x2 +#define PERIPH_RATIO 0x7 +#define ACP_RATIO 0x7 +#define CPUD_RATIO 0x1 +#define ARM_RATIO 0x0 + +#elif defined(CONFIG_CLK_ARM_800_APLL_800) + +#define ARM2_RATIO 0x0 +#define APLL_RATIO 0x1 +#define PCLK_DBG_RATIO 0x1 +#define ATB_RATIO 0x3 +#define PERIPH_RATIO 0x7 +#define ACP_RATIO 0x7 +#define CPUD_RATIO 0x2 +#define ARM_RATIO 0x0 + +#elif defined(CONFIG_CLK_ARM_1000_APLL_1000) + +#define ARM2_RATIO 0x0 +#define APLL_RATIO 0x1 +#define PCLK_DBG_RATIO 0x1 +#define ATB_RATIO 0x4 +#define PERIPH_RATIO 0x7 +#define ACP_RATIO 0x7 +#define CPUD_RATIO 0x2 +#define ARM_RATIO 0x0 + +#elif defined(CONFIG_CLK_ARM_1200_APLL_1200) + +#define ARM2_RATIO 0x0 +#define APLL_RATIO 0x3 +#define PCLK_DBG_RATIO 0x1 +#define ATB_RATIO 0x5 +#define PERIPH_RATIO 0x7 +#define ACP_RATIO 0x7 +#define CPUD_RATIO 0x3 +#define ARM_RATIO 0x0 + +#elif defined(CONFIG_CLK_ARM_1400_APLL_1400) + +#define ARM2_RATIO 0x0 +#define APLL_RATIO 0x3 +#define PCLK_DBG_RATIO 0x1 +#define ATB_RATIO 0x6 +#define PERIPH_RATIO 0x7 +#define ACP_RATIO 0x7 +#define CPUD_RATIO 0x3 +#define ARM_RATIO 0x0 + +#elif defined(CONFIG_CLK_ARM_1700_APLL_1700) + +#define ARM2_RATIO 0x0 +#define APLL_RATIO 0x3 +#define PCLK_DBG_RATIO 0x1 +#define ATB_RATIO 0x6 +#define PERIPH_RATIO 0x7 +#define ACP_RATIO 0x7 +#define CPUD_RATIO 0x3 +#define ARM_RATIO 0x0 +#endif + +/* CLK_DIV_CPU0_VAL */ +#define CLK_DIV_CPU0_VAL ((ARM2_RATIO << 28) \ + | (APLL_RATIO << 24) \ + | (PCLK_DBG_RATIO << 20) \ + | (ATB_RATIO << 16) \ + | (PERIPH_RATIO << 12) \ + | (ACP_RATIO << 8) \ + | (CPUD_RATIO << 4) \ + | (ARM_RATIO)) + +/* CLK_DIV_CPU1 */ +#define HPM_RATIO 0x2 +#define COPY_RATIO 0x0 + +/* CLK_DIV_CPU1 = 0x00000003 */ +#define CLK_DIV_CPU1_VAL ((HPM_RATIO << 4) \ + | (COPY_RATIO)) + +/* CLK_SRC_CORE0 */ +#define CLK_SRC_CORE0_VAL 0x00000000 + +/* CLK_SRC_CORE1 */ +#define CLK_SRC_CORE1_VAL 0x100 + +/* CLK_DIV_CORE0 */ +#define CLK_DIV_CORE0_VAL 0x00120000 + +/* CLK_DIV_CORE1 */ +#define CLK_DIV_CORE1_VAL 0x07070700 + +/* CLK_DIV_SYSRGT */ +#define CLK_DIV_SYSRGT_VAL 0x00000111 + +/* CLK_DIV_ACP */ +#define CLK_DIV_ACP_VAL 0x12 + +/* CLK_DIV_SYSLFT */ +#define CLK_DIV_SYSLFT_VAL 0x00000311 + +/* CLK_SRC_CDREX */ +#define CLK_SRC_CDREX_VAL 0x1 + +/* CLK_DIV_CDREX */ +#define MCLK_DPHY_RATIO 0x1 +#define MCLK_CDREX_RATIO 0x1 +#define ACLK_C2C_200_RATIO 0x1 +#define C2C_CLK_400_RATIO 0x1 +#define PCLK_CDREX_RATIO 0x1 +#define ACLK_CDREX_RATIO 0x1 + +#define CLK_DIV_CDREX_VAL ((MCLK_DPHY_RATIO << 20) \ + | (MCLK_CDREX_RATIO << 16) \ + | (ACLK_C2C_200_RATIO << 12) \ + | (C2C_CLK_400_RATIO << 8) \ + | (PCLK_CDREX_RATIO << 4) \ + | (ACLK_CDREX_RATIO)) \ +/* CLK_SRC_TOP0 */ +#define MUX_ACLK_300_GSCL_SEL 0x0 +#define MUX_ACLK_300_GSCL_MID_SEL 0x0 +#define MUX_ACLK_400_G3D_MID_SEL 0x0 +#define MUX_ACLK_333_SEL 0x0 +#define MUX_ACLK_300_DISP1_SEL 0x0 +#define MUX_ACLK_300_DISP1_MID_SEL 0x0 +#define MUX_ACLK_200_SEL 0x0 +#define MUX_ACLK_166_SEL 0x0 +#define CLK_SRC_TOP0_VAL ((MUX_ACLK_300_GSCL_SEL << 25) \ + | (MUX_ACLK_300_GSCL_MID_SEL << 24) \ + | (MUX_ACLK_400_G3D_MID_SEL << 20) \ + | (MUX_ACLK_333_SEL << 16) \ + | (MUX_ACLK_300_DISP1_SEL << 15) \ + | (MUX_ACLK_300_DISP1_MID_SEL << 14) \ + | (MUX_ACLK_200_SEL << 12) \ + | (MUX_ACLK_166_SEL << 8)) + +/* CLK_SRC_TOP1 */ +#define MUX_ACLK_400_G3D_SEL 0x1 +#define MUX_ACLK_400_ISP_SEL 0x0 +#define MUX_ACLK_400_IOP_SEL 0x0 +#define MUX_ACLK_MIPI_HSI_TXBASE_SEL 0x0 +#define MUX_ACLK_300_GSCL_MID1_SEL 0x0 +#define MUX_ACLK_300_DISP1_MID1_SEL 0x0 +#define CLK_SRC_TOP1_VAL ((MUX_ACLK_400_G3D_SEL << 28) \ + |(MUX_ACLK_400_ISP_SEL << 24) \ + |(MUX_ACLK_400_IOP_SEL << 20) \ + |(MUX_ACLK_MIPI_HSI_TXBASE_SEL << 16) \ + |(MUX_ACLK_300_GSCL_MID1_SEL << 12) \ + |(MUX_ACLK_300_DISP1_MID1_SEL << 8)) + +/* CLK_SRC_TOP2 */ +#define MUX_GPLL_SEL 0x1 +#define MUX_BPLL_USER_SEL 0x0 +#define MUX_MPLL_USER_SEL 0x0 +#define MUX_VPLL_SEL 0x1 +#define MUX_EPLL_SEL 0x1 +#define MUX_CPLL_SEL 0x1 +#define VPLLSRC_SEL 0x0 +#define CLK_SRC_TOP2_VAL ((MUX_GPLL_SEL << 28) \ + | (MUX_BPLL_USER_SEL << 24) \ + | (MUX_MPLL_USER_SEL << 20) \ + | (MUX_VPLL_SEL << 16) \ + | (MUX_EPLL_SEL << 12) \ + | (MUX_CPLL_SEL << 8) \ + | (VPLLSRC_SEL)) +/* CLK_SRC_TOP3 */ +#define MUX_ACLK_333_SUB_SEL 0x1 +#define MUX_ACLK_400_SUB_SEL 0x1 +#define MUX_ACLK_266_ISP_SUB_SEL 0x1 +#define MUX_ACLK_266_GPS_SUB_SEL 0x0 +#define MUX_ACLK_300_GSCL_SUB_SEL 0x1 +#define MUX_ACLK_266_GSCL_SUB_SEL 0x1 +#define MUX_ACLK_300_DISP1_SUB_SEL 0x1 +#define MUX_ACLK_200_DISP1_SUB_SEL 0x1 +#define CLK_SRC_TOP3_VAL ((MUX_ACLK_333_SUB_SEL << 24) \ + | (MUX_ACLK_400_SUB_SEL << 20) \ + | (MUX_ACLK_266_ISP_SUB_SEL << 16) \ + | (MUX_ACLK_266_GPS_SUB_SEL << 12) \ + | (MUX_ACLK_300_GSCL_SUB_SEL << 10) \ + | (MUX_ACLK_266_GSCL_SUB_SEL << 8) \ + | (MUX_ACLK_300_DISP1_SUB_SEL << 6) \ + | (MUX_ACLK_200_DISP1_SUB_SEL << 4)) + +/* CLK_DIV_TOP0 */ +#define ACLK_300_DISP1_RATIO 0x2 +#define ACLK_400_G3D_RATIO 0x0 +#define ACLK_333_RATIO 0x0 +#define ACLK_266_RATIO 0x2 +#define ACLK_200_RATIO 0x3 +#define ACLK_166_RATIO 0x1 +#define ACLK_133_RATIO 0x1 +#define ACLK_66_RATIO 0x5 + +#define CLK_DIV_TOP0_VAL ((ACLK_300_DISP1_RATIO << 28) \ + | (ACLK_400_G3D_RATIO << 24) \ + | (ACLK_333_RATIO << 20) \ + | (ACLK_266_RATIO << 16) \ + | (ACLK_200_RATIO << 12) \ + | (ACLK_166_RATIO << 8) \ + | (ACLK_133_RATIO << 4) \ + | (ACLK_66_RATIO)) + +/* CLK_DIV_TOP1 */ +#define ACLK_MIPI_HSI_TX_BASE_RATIO 0x3 +#define ACLK_66_PRE_RATIO 0x1 +#define ACLK_400_ISP_RATIO 0x1 +#define ACLK_400_IOP_RATIO 0x1 +#define ACLK_300_GSCL_RATIO 0x2 + +#define CLK_DIV_TOP1_VAL ((ACLK_MIPI_HSI_TX_BASE_RATIO << 28) \ + | (ACLK_66_PRE_RATIO << 24) \ + | (ACLK_400_ISP_RATIO << 20) \ + | (ACLK_400_IOP_RATIO << 16) \ + | (ACLK_300_GSCL_RATIO << 12)) + +/* APLL_LOCK */ +#define APLL_LOCK_VAL (0x546) +/* MPLL_LOCK */ +#define MPLL_LOCK_VAL (0x546) +/* CPLL_LOCK */ +#define CPLL_LOCK_VAL (0x546) +/* GPLL_LOCK */ +#define GPLL_LOCK_VAL (0x546) +/* EPLL_LOCK */ +#define EPLL_LOCK_VAL (0x3A98) +/* VPLL_LOCK */ +#define VPLL_LOCK_VAL (0x3A98) +/* BPLL_LOCK */ +#define BPLL_LOCK_VAL (0x546) + +/* CLK_SRC_PERIC0 */ +#define PWM_SEL 0 +#define UART3_SEL 6 +#define UART2_SEL 6 +#define UART1_SEL 6 +#define UART0_SEL 6 +/* SRC_CLOCK = SCLK_MPLL */ +#define CLK_SRC_PERIC0_VAL ((PWM_SEL << 24) \ + | (UART3_SEL << 12) \ + | (UART2_SEL<< 8) \ + | (UART1_SEL << 4) \ + | (UART0_SEL)) + +/* CLK_DIV_PERIL0 */ +#define UART5_RATIO 7 +#define UART4_RATIO 7 +#define UART3_RATIO 7 +#define UART2_RATIO 7 +#define UART1_RATIO 7 +#define UART0_RATIO 7 + +#define CLK_DIV_PERIC0_VAL ((UART3_RATIO << 12) \ + | (UART2_RATIO << 8) \ + | (UART1_RATIO << 4) \ + | (UART0_RATIO)) +/* CLK_SRC_LEX */ +#define CLK_SRC_LEX_VAL 0x0 + +/* CLK_DIV_LEX */ +#define CLK_DIV_LEX_VAL 0x10 + +/* CLK_DIV_R0X */ +#define CLK_DIV_R0X_VAL 0x10 + +/* CLK_DIV_L0X */ +#define CLK_DIV_R1X_VAL 0x10 + +/* CLK_DIV_ISP0 */ +#define CLK_DIV_ISP0_VAL 0x31 + +/* CLK_DIV_ISP1 */ +#define CLK_DIV_ISP1_VAL 0x0 + +/* CLK_DIV_ISP2 */ +#define CLK_DIV_ISP2_VAL 0x1 + +#define MPLL_DEC (MPLL_MDIV * MPLL_MDIV / (MPLL_PDIV * 2^(MPLL_SDIV-1))) + +#define SCLK_UART MPLL_DEC / (UART1_RATIO+1) + +#define UART_UBRDIV_VAL 0x35 /* (SCLK_UART/(115200*16) -1) */ +#define UART_UDIVSLOT_VAL 0x4 /*((((SCLK_UART*10/(115200*16) -10))%10)*16/10)*/ + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Exynos5250.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Exynos5250.h new file mode 100644 index 000000000..b0e473d9e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Exynos5250.h @@ -0,0 +1,730 @@ +/* + * (C) Copyright 2012 Samsung Electronics Co. Ltd + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + */ + +#ifndef _EXYNOS5250_CPU_H +#define _EXYNOS5250_CPU_H + +/* EXYNOS5250 */ +#define EXYNOS5250_PRO_ID 0x10000000 +#define EXYNOS5250_SYSREG_BASE 0x10050000 +#define EXYNOS5250_POWER_BASE 0x10040000 +#define EXYNOS5250_CLOCK_BASE 0x10010000 +#define EXYNOS5250_SROM_BASE 0x12250000 +#define EXYNOS5250_HSMMC_BASE 0x12200000 +#define EXYNOS5250_PWMTIMER_BASE 0x12DD0000 +#define EXYNOS5250_INF_REG_BASE 0x10040800 +#define EXYNOS5250_TZPC_BASE 0x10100000 +#define EXYNOS5250_UART_BASE 0x12C00000 + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + + +#define __REG(x) (*(unsigned int *)(x)) + +/* + * CHIP ID + */ +#define CHIP_ID_BASE EXYNOS5250_PRO_ID +#define PRO_ID_OFFSET 0x0 +#define PRO_ID __REG(CHIP_ID_BASE+PRO_ID_OFFSET) + +/* + * SYSREG + */ +#define USB_CFG_OFFSET 0x230 +#define USB_CFG_REG (EXYNOS5250_SYSREG_BASE + USB_CFG_OFFSET) + +/* + * POWER + */ +#define ELFIN_POWER_BASE EXYNOS5250_POWER_BASE +#define OMR_OFFSET 0x0 +#define SW_RST_REG_OFFSET 0x400 +#define SW_RST_REG __REG(EXYNOS5250_POWER_BASE + SW_RST_REG_OFFSET) + +#define INF_REG_BASE EXYNOS5250_INF_REG_BASE + +#define INF_REG0_OFFSET 0x00 +#define INF_REG1_OFFSET 0x04 +#define INF_REG2_OFFSET 0x08 +#define INF_REG3_OFFSET 0x0C +#define INF_REG4_OFFSET 0x10 +#define INF_REG5_OFFSET 0x14 +#define INF_REG6_OFFSET 0x18 +#define INF_REG7_OFFSET 0x1C + +#define INF_REG0_REG __REG(INF_REG_BASE+INF_REG0_OFFSET) +#define INF_REG1_REG __REG(INF_REG_BASE+INF_REG1_OFFSET) +#define INF_REG2_REG __REG(INF_REG_BASE+INF_REG2_OFFSET) +#define INF_REG3_REG __REG(INF_REG_BASE+INF_REG3_OFFSET) +#define INF_REG4_REG __REG(INF_REG_BASE+INF_REG4_OFFSET) +#define INF_REG5_REG __REG(INF_REG_BASE+INF_REG5_OFFSET) +#define INF_REG6_REG __REG(INF_REG_BASE+INF_REG6_OFFSET) +#define INF_REG7_REG __REG(INF_REG_BASE+INF_REG7_OFFSET) + +#define USB_DEVICE_PHY_CONTROL_OFFSET 0x0704 +#define USB_DEVICE_PHY_CONTROL (EXYNOS5250_POWER_BASE+USB_DEVICE_PHY_CONTROL_OFFSET) + +/* Define Mode */ +#define S5P_CHECK_SLEEP 0x00000BAD +#define S5P_CHECK_DIDLE 0xBAD00000 +#define S5P_CHECK_LPA 0xABAD0000 + +/* + * CLOCK + */ +#define ELFIN_CLOCK_BASE EXYNOS5250_CLOCK_BASE + +#define APLL_LOCK_OFFSET 0x00000 +#define APLL_CON0_OFFSET 0x00100 +#define APLL_CON1_OFFSET 0x00104 +#define CLK_SRC_CPU_OFFSET 0x00200 +#define CLK_MUX_STAT_CPU_OFFSET 0x00400 +#define CLK_DIV_CPU0_OFFSET 0x00500 +#define CLK_DIV_CPU1_OFFSET 0x00504 +#define CLK_DIV_STAT_CPU0_OFFSET 0x00600 +#define CLK_DIV_STAT_CPU1_OFFSET 0x00604 +#define CLK_GATE_SCLK_CPU_OFFSET 0x00800 +#define CLKOUT_CMU_CPU_OFFSET 0x00A00 +#define CLKOUT_CMU_CPU_DIV_STAT_OFFSET 0x00A04 +#define ARMCLK_STOPCTRL_OFFSET 0x01000 +#define ATCLK_STOPCTRL_OFFSET 0x01004 +#define PARITYFAIL_STATUS_OFFSET 0x01010 +#define PARITYFAIL_CLEAR_OFFSET 0x01014 +#define PWR_CTRL_OFFSET 0x01020 +#define PWR_CTRL2_OFFSET 0x01024 +#define APLL_CON0_L8_OFFSET 0x01100 +#define APLL_CON0_L7_OFFSET 0x01104 +#define APLL_CON0_L6_OFFSET 0x01108 +#define APLL_CON0_L5_OFFSET 0x0110C +#define APLL_CON0_L4_OFFSET 0x01110 +#define APLL_CON0_L3_OFFSET 0x01114 +#define APLL_CON0_L2_OFFSET 0x01118 +#define APLL_CON0_L1_OFFSET 0x0111C +#define IEM_CONTROL_OFFSET 0x01120 +#define APLL_CON1_L8_OFFSET 0x01200 +#define APLL_CON1_L7_OFFSET 0x01204 +#define APLL_CON1_L6_OFFSET 0x01208 +#define APLL_CON1_L5_OFFSET 0x0120C +#define APLL_CON1_L4_OFFSET 0x01210 +#define APLL_CON1_L3_OFFSET 0x01214 +#define APLL_CON1_L2_OFFSET 0x01218 +#define APLL_CON1_L1_OFFSET 0x0121C +#define CLKDIV_IEM_L8_OFFSET 0x01300 +#define CLKDIV_IEM_L7_OFFSET 0x01304 +#define CLKDIV_IEM_L6_OFFSET 0x01308 +#define CLKDIV_IEM_L5_OFFSET 0x0130C +#define CLKDIV_IEM_L4_OFFSET 0x01310 +#define CLKDIV_IEM_L3_OFFSET 0x01314 +#define CLKDIV_IEM_L2_OFFSET 0x01318 +#define CLKDIV_IEM_L1_OFFSET 0x0131C +#define MPLL_LOCK_OFFSET 0x04000 +#define MPLL_CON0_OFFSET 0x04100 +#define MPLL_CON1_OFFSET 0x04104 +#define CLK_SRC_CORE0_OFFSET 0x04200 +#define CLK_SRC_CORE1_OFFSET 0x04204 +#define CLK_SRC_MASK_CORE0_OFFSET 0x04300 +#define CLK_MUX_STAT_CORE1_OFFSET 0x04404 +#define CLK_DIV_CORE0_OFFSET 0x04500 +#define CLK_DIV_CORE1_OFFSET 0x04504 +#define CLK_DIV_STAT_CORE0_OFFSET 0x04600 +#define CLK_DIV_STAT_CORE1_OFFSET 0x04604 +#define CLK_GATE_IP_CORE_OFFSET 0x04900 +#define CLKOUT_CMU_CORE_OFFSET 0x04A00 +#define CLKOUT_CMU_CORE_DIV_STAT_OFFSET 0x04A04 +#define DCGIDX_MAP0_OFFSET 0x05000 +#define DCGIDX_MAP1_OFFSET 0x05004 +#define DCGIDX_MAP2_OFFSET 0x05008 +#define DCGPERF_MAP0_OFFSET 0x05020 +#define DCGPERF_MAP1_OFFSET 0x05024 +#define DVCIDX_MAP_OFFSET 0x05040 +#define FREQ_CPU_OFFSET 0x05060 +#define FREQ_DPM_OFFSET 0x05064 +#define DVSEMCLK_EN_OFFSET 0x05080 +#define MAXPERF_OFFSET 0x05084 +#define CLK_DIV_ACP_OFFSET 0x08500 +#define CLK_DIV_STAT_ACP_OFFSET 0x08600 +#define CLK_GATE_IP_ACP_OFFSET 0x08800 +#define CLKOUT_CMU_ACP_OFFSET 0x08A00 +#define CLKOUT_CMU_ACP_DIV_STAT_OFFSET 0x08A04 +#define CLK_DIV_ISP0_OFFSET 0x0C300 +#define CLK_DIV_ISP1_OFFSET 0x0C304 +#define CLK_DIV_ISP2_OFFSET 0x0C308 +#define CLK_DIV_STAT_ISP0_OFFSET 0x0C400 +#define CLK_DIV_STAT_ISP1_OFFSET 0x0C404 +#define CLK_DIV_STAT_ISP2_OFFSET 0x0C408 +#define CLK_GATE_IP_ISP0_OFFSET 0x0C800 +#define CLK_GATE_IP_ISP1_OFFSET 0x0C804 +#define CLK_GATE_SCLK_ISP_OFFSET 0x0C900 +#define MCUISP_PWR_CTRL_OFFSET 0x0C910 +#define CLKOUT_CMU_ISP_OFFSET 0x0CA00 +#define CLKOUT_CMU_ISP_DIV_STAT_OFFSET 0x0CA04 +#define CPLL_LOCK_OFFSET 0x10020 +#define EPLL_LOCK_OFFSET 0x10030 +#define VPLL_LOCK_OFFSET 0x10040 +#define CPLL_CON0_OFFSET 0x10120 +#define CPLL_CON1_OFFSET 0x10124 +#define EPLL_CON0_OFFSET 0x10130 +#define EPLL_CON1_OFFSET 0x10134 +#define EPLL_CON2_OFFSET 0x10138 +#define VPLL_CON0_OFFSET 0x10140 +#define VPLL_CON1_OFFSET 0x10144 +#define VPLL_CON2_OFFSET 0x10148 +#define CLK_SRC_TOP0_OFFSET 0x10210 +#define CLK_SRC_TOP1_OFFSET 0x10214 +#define CLK_SRC_TOP2_OFFSET 0x10218 +#define CLK_SRC_TOP3_OFFSET 0x1021C +#define CLK_SRC_GSCL_OFFSET 0x10220 +#define CLK_SRC_DISP1_0_OFFSET 0x1022C +#define CLK_SRC_DISP1_1_OFFSET 0x10230 +#define CLK_SRC_MAU_OFFSET 0x10240 +#define CLK_SRC_FSYS_OFFSET 0x10244 +#define CLK_SRC_PERIC0_OFFSET 0x10250 +#define CLK_SRC_PERIC1_OFFSET 0x10254 +#define SCLK_SRC_ISP_OFFSET 0x10270 +#define CLK_SRC_MASK_TOP_OFFSET 0x10310 +#define CLK_SRC_MASK_GSCL_OFFSET 0x10320 +#define CLK_SRC_MASK_DISP1_0_OFFSET 0x1032C +#define CLK_SRC_MASK_DISP1_1_OFFSET 0x10330 +#define CLK_SRC_MASK_MAU_OFFSET 0x10334 +#define CLK_SRC_MASK_FSYS_OFFSET 0x10340 +#define CLK_SRC_MASK_PERIC0_OFFSET 0x10350 +#define CLK_SRC_MASK_PERIC1_OFFSET 0x10354 +#define SCLK_SRC_MASK_ISP_OFFSET 0x10370 +#define CLK_MUX_STAT_TOP0_OFFSET 0x10410 +#define CLK_MUX_STAT_TOP1_OFFSET 0x10414 +#define CLK_MUX_STAT_TOP2_OFFSET 0x10418 +#define CLK_MUX_STAT_TOP3_OFFSET 0x1041C +#define CLK_DIV_TOP0_OFFSET 0x10510 +#define CLK_DIV_TOP1_OFFSET 0x10514 +#define CLK_DIV_GSCL_OFFSET 0x10520 +#define CLK_DIV_DISP1_0_OFFSET 0x1052C +#define CLK_DIV_DISP1_1_OFFSET 0x10530 +#define CLK_DIV_GEN_OFFSET 0x1053C +#define CLK_DIV_MAU_OFFSET 0x10544 +#define CLK_DIV_FSYS0_OFFSET 0x10548 +#define CLK_DIV_FSYS1_OFFSET 0x1054C +#define CLK_DIV_FSYS2_OFFSET 0x10550 +#define CLK_DIV_FSYS3_OFFSET 0x10554 +#define CLK_DIV_PERIC0_OFFSET 0x10558 +#define CLK_DIV_PERIC1_OFFSET 0x1055C +#define CLK_DIV_PERIC2_OFFSET 0x10560 +#define CLK_DIV_PERIC3_OFFSET 0x10564 +#define CLK_DIV_PERIC4_OFFSET 0x10568 +#define CLK_DIV_PERIC5_OFFSET 0x1056C +#define SCLK_DIV_ISP_OFFSET 0x10580 +#define CLKDIV2_RATIO0_OFFSET 0x10590 +#define CLKDIV2_RATIO1_OFFSET 0x10594 +#define CLKDIV4_RATIO_OFFSET 0x105A0 +#define CLK_DIV_STAT_TOP0_OFFSET 0x10610 +#define CLK_DIV_STAT_TOP1_OFFSET 0x10614 +#define CLK_DIV_STAT_GSCL_OFFSET 0x10620 +#define CLK_DIV_STAT_DISP1_0_OFFSET 0x1062C +#define CLK_DIV_STAT_DISP1_1_OFFSET 0x10630 +#define CLK_DIV_STAT_GEN_OFFSET 0x1063C +#define CLK_DIV_STAT_MAUDIO_OFFSET 0x10644 +#define CLK_DIV_STAT_FSYS0_OFFSET 0x10648 +#define CLK_DIV_STAT_FSYS1_OFFSET 0x1064C +#define CLK_DIV_STAT_FSYS2_OFFSET 0x10650 +#define CLK_DIV_STAT_FSYS3_OFFSET 0x10654 +#define CLK_DIV_STAT_PERIC0_OFFSET 0x10658 +#define CLK_DIV_STAT_PERIC1_OFFSET 0x1065C +#define CLK_DIV_STAT_PERIC2_OFFSET 0x10660 +#define CLK_DIV_STAT_PERIC3_OFFSET 0x10664 +#define CLK_DIV_STAT_PERIC4_OFFSET 0x10668 +#define CLK_DIV_STAT_PERIC5_OFFSET 0x1066C +#define SCLK_DIV_STAT_ISP_OFFSET 0x10680 +#define CLKDIV2_STAT0_OFFSET 0x10690 +#define CLKDIV2_STAT1_OFFSET 0x10694 +#define CLKDIV4_STAT_OFFSET 0x106A0 +#define CLK_GATE_TOP_SCLK_DISP1_OFFSET 0x10828 +#define CLK_GATE_TOP_SCLK_GEN_OFFSET 0x1082C +#define CLK_GATE_TOP_SCLK_MAU_OFFSET 0x1083C +#define CLK_GATE_TOP_SCLK_FSYS_OFFSET 0x10840 +#define CLK_GATE_TOP_SCLK_PERIC_OFFSET 0x10850 +#define CLK_GATE_TOP_SCLK_ISP_OFFSET 0x10870 +#define CLK_GATE_IP_GSCL_OFFSET 0x10920 +#define CLK_GATE_IP_DISP1_OFFSET 0x10928 +#define CLK_GATE_IP_MFC_OFFSET 0x1092C +#define CLK_GATE_IP_G3D_OFFSET 0x10930 +#define CLK_GATE_IP_GEN_OFFSET 0x10934 +#define CLK_GATE_IP_FSYS_OFFSET 0x10944 +#define CLK_GATE_IP_GPS_OFFSET 0x1094C +#define CLK_GATE_IP_PERIC_OFFSET 0x10950 +#define CLK_GATE_IP_PERIS_OFFSET 0x10960 +#define CLK_GATE_BLOCK_OFFSET 0x10980 +#define CLKOUT_CMU_TOP_OFFSET 0x10A00 +#define CLKOUT_CMU_TOP_DIV_STAT_OFFSET 0x10A04 +#define CLK_SRC_LEX_OFFSET 0x14200 +#define CLK_DIV_LEX_OFFSET 0x14500 +#define CLK_DIV_STAT_LEX_OFFSET 0x14600 +#define CLK_GATE_IP_LEX_OFFSET 0x14800 +#define CLKOUT_CMU_LEX_OFFSET 0x14A00 +#define CLKOUT_CMU_LEX_DIV_STAT_OFFSET 0x14A04 +#define CLK_DIV_R0X_OFFSET 0x18500 +#define CLK_DIV_STAT_R0X_OFFSET 0x18600 +#define CLK_GATE_IP_R0X_OFFSET 0x18800 +#define CLKOUT_CMU_R0X_OFFSET 0x18A00 +#define CLKOUT_CMU_R0X_DIV_STAT_OFFSET 0x18A04 +#define CLK_DIV_R1X_OFFSET 0x1C500 +#define CLK_DIV_STAT_R1X_OFFSET 0x1C600 +#define CLK_GATE_IP_R1X_OFFSET 0x1C800 +#define CLKOUT_CMU_R1X_OFFSET 0x1CA00 +#define CLKOUT_CMU_R1X_DIV_STAT_OFFSET 0x1CA04 +#define BPLL_LOCK_OFFSET 0x20010 +#define BPLL_CON0_OFFSET 0x20110 +#define BPLL_CON1_OFFSET 0x20114 +#define CLK_SRC_CDREX_OFFSET 0x20200 +#define CLK_MUX_STAT_CDREX_OFFSET 0x20400 +#define CLK_DIV_CDREX_OFFSET 0x20500 +#define CLK_DIV_CDREX2_OFFSET 0x20504 +#define CLK_DIV_STAT_CDREX_OFFSET 0x20600 +#define CLK_GATE_IP_CDREX_OFFSET 0x20900 +#define C2C_MONITOR_OFFSET 0x20910 +#define DMC_PWR_CTRL 0x20914 +#define DREX2_PAUSE_OFFSET 0x2091C +#define CLKOUT_CMU_CDREX_OFFSET 0x20A00 +#define CLKOUT_CMU_CDREX_DIV_STAT_OFFSET 0x20A04 +#define LPDDR3PHY_CTRL 0x20A10 + +#define CLK_SRC_FSYS __REG(ELFIN_CLOCK_BASE+CLK_SRC_FSYS_OFFSET) +#define CLK_DIV_FSYS1 __REG(ELFIN_CLOCK_BASE+CLK_DIV_FSYS1_OFFSET) +#define CLK_DIV_FSYS2 __REG(ELFIN_CLOCK_BASE+CLK_DIV_FSYS2_OFFSET) +#define CLK_DIV_FSYS3 __REG(ELFIN_CLOCK_BASE+CLK_DIV_FSYS3_OFFSET) +#define APLL_CON0_REG __REG(ELFIN_CLOCK_BASE+APLL_CON0_OFFSET) +#define MPLL_CON0_REG __REG(ELFIN_CLOCK_BASE+MPLL_CON0_OFFSET) +#define EPLL_CON0_REG __REG(ELFIN_CLOCK_BASE+EPLL_CON0_OFFSET) +#define VPLL_CON0_REG __REG(ELFIN_CLOCK_BASE+VPLL_CON0_OFFSET) + +#define FIMD1_SCLKMPLL (0x06) +#define FIMD1_CLK_DIV (0x00) + +#define CLK_GATE_FIMD1_MASK (0x01 << 0x00) +#define CLK_SRC_FIMD1_MASK (0x0F << 0x00) +#define CLK_DIV_FIMD1_MASK (0x0F << 0x00) + +#define CLK_SRC_FIMD1_SEL(x) ((x) << 0x00) +#define CLK_DIV_FIMD1_SEL(x) ((x) << 0x00) +#define CLK_SRC_DISP1_0_UNMASK (0x01 << 0x00) + +#define CLK_GATE_DSIM1_MASK (0x01 << 0x03) + +/* + * TZPC + */ +#define TZPC0_OFFSET 0x00000 +#define TZPC1_OFFSET 0x10000 +#define TZPC2_OFFSET 0x20000 +#define TZPC3_OFFSET 0x30000 +#define TZPC4_OFFSET 0x40000 +#define TZPC5_OFFSET 0x50000 +#define TZPC6_OFFSET 0x60000 +#define TZPC7_OFFSET 0x70000 +#define TZPC8_OFFSET 0x80000 +#define TZPC9_OFFSET 0x90000 + +#define ELFIN_TZPC0_BASE (EXYNOS5250_TZPC_BASE + TZPC0_OFFSET) +#define ELFIN_TZPC1_BASE (EXYNOS5250_TZPC_BASE + TZPC1_OFFSET) +#define ELFIN_TZPC2_BASE (EXYNOS5250_TZPC_BASE + TZPC2_OFFSET) +#define ELFIN_TZPC3_BASE (EXYNOS5250_TZPC_BASE + TZPC3_OFFSET) +#define ELFIN_TZPC4_BASE (EXYNOS5250_TZPC_BASE + TZPC4_OFFSET) +#define ELFIN_TZPC5_BASE (EXYNOS5250_TZPC_BASE + TZPC5_OFFSET) +#define ELFIN_TZPC6_BASE (EXYNOS5250_TZPC_BASE + TZPC6_OFFSET) +#define ELFIN_TZPC7_BASE (EXYNOS5250_TZPC_BASE + TZPC7_OFFSET) +#define ELFIN_TZPC8_BASE (EXYNOS5250_TZPC_BASE + TZPC8_OFFSET) +#define ELFIN_TZPC9_BASE (EXYNOS5250_TZPC_BASE + TZPC9_OFFSET) + +#define TZPC_DECPROT0SET_OFFSET 0x804 +#define TZPC_DECPROT1SET_OFFSET 0x810 +#define TZPC_DECPROT2SET_OFFSET 0x81C +#define TZPC_DECPROT3SET_OFFSET 0x828 + +/* + * Memory controller + */ +#define ELFIN_SROM_BASE EXYNOS5250_SROM_BASE + +#define SROM_BW_REG __REG(ELFIN_SROM_BASE+0x0) +#define SROM_BC0_REG __REG(ELFIN_SROM_BASE+0x4) +#define SROM_BC1_REG __REG(ELFIN_SROM_BASE+0x8) +#define SROM_BC2_REG __REG(ELFIN_SROM_BASE+0xC) +#define SROM_BC3_REG __REG(ELFIN_SROM_BASE+0x10) + +/* + * SDRAM Controller + */ + +/* DMC control register */ +#define DMC_CTRL_BASE 0x10DD0000 + +#define DMC_CONCONTROL 0x00 +#define DMC_MEMCONTROL 0x04 +#define DMC_MEMCONFIG0 0x08 +#define DMC_MEMCONFIG1 0x0C +#define DMC_DIRECTCMD 0x10 +#define DMC_PRECHCONFIG 0x14 +#define DMC_PHYCONTROL0 0x18 +#define DMC_PWRDNCONFIG 0x28 +#define DMC_TIMINGPZQ 0x2C +#define DMC_TIMINGAREF 0x30 +#define DMC_TIMINGROW 0x34 +#define DMC_TIMINGDATA 0x38 +#define DMC_TIMINGPOWER 0x3C +#define DMC_PHYSTATUS 0x40 +#define DMC_CHIPSTATUS_CH0 0x48 +#define DMC_CHIPSTATUS_CH1 0x4C +#define DMC_MRSTATUS 0x54 +#define DMC_QOSCONTROL0 0x60 +#define DMC_QOSCONTROL1 0x68 +#define DMC_QOSCONTROL2 0x70 +#define DMC_QOSCONTROL3 0x78 +#define DMC_QOSCONTROL4 0x80 +#define DMC_QOSCONTROL5 0x88 +#define DMC_QOSCONTROL6 0x90 +#define DMC_QOSCONTROL7 0x98 +#define DMC_QOSCONTROL8 0xA0 +#define DMC_QOSCONTROL9 0xA8 +#define DMC_QOSCONTROL10 0xB0 +#define DMC_QOSCONTROL11 0xB8 +#define DMC_QOSCONTROL12 0xC0 +#define DMC_QOSCONTROL13 0xC8 +#define DMC_QOSCONTROL14 0xD0 +#define DMC_QOSCONTROL15 0xD8 +#define DMC_IVCONTROL 0xF0 +#define DMC_WRTRA_CONFIG 0x00F4 +#define DMC_RDLVL_CONFIG 0x00F8 +#define DMC_BRBRSVCONTROL 0x0100 +#define DMC_BRBRSVCONFIG 0x0104 +#define DMC_BRBQOSCONFIG 0x0108 +#define DMC_MEMBASECONFIG0 0x010C +#define DMC_MEMBASECONFIG1 0x0110 +#define DMC_WRLVL_CONFIG 0x0120 +#define DMC_PMNC_PPC 0xE000 +#define DMC_CNTENS_PPC 0xE010 +#define DMC_CNTENC_PPC 0xE020 +#define DMC_INTENS_PPC 0xE030 +#define DMC_INTENC_PPC 0xE040 +#define DMC_FLAG_PPC 0xE050 +#define DMC_CCNT_PPC 0xE100 +#define DMC_PMCNT0_PPC 0xE110 +#define DMC_PMCNT1_PPC 0xE120 +#define DMC_PMCNT2_PPC 0xE130 +#define DMC_PMCNT3_PPC 0xE140 + +/* PHY Control Register */ +#define PHY0_CTRL_BASE 0x10C00000 +#define PHY1_CTRL_BASE 0x10C10000 + +#define DMC_PHY_CON0 0x00 +#define DMC_PHY_CON1 0x04 +#define DMC_PHY_CON2 0x08 +#define DMC_PHY_CON3 0x0C +#define DMC_PHY_CON4 0x10 +#define DMC_PHY_CON6 0x18 +#define DMC_PHY_CON8 0x20 +#define DMC_PHY_CON10 0x28 +#define DMC_PHY_CON11 0x2C +#define DMC_PHY_CON12 0x30 +#define DMC_PHY_CON13 0x34 +#define DMC_PHY_CON14 0x38 +#define DMC_PHY_CON15 0x3C +#define DMC_PHY_CON16 0x40 +#define DMC_PHY_CON17 0x48 +#define DMC_PHY_CON18 0x4C +#define DMC_PHY_CON19 0x50 +#define DMC_PHY_CON20 0x54 +#define DMC_PHY_CON21 0x58 +#define DMC_PHY_CON22 0x5C +#define DMC_PHY_CON23 0x60 +#define DMC_PHY_CON24 0x64 +#define DMC_PHY_CON25 0x68 +#define DMC_PHY_CON26 0x6C +#define DMC_PHY_CON27 0x70 +#define DMC_PHY_CON28 0x74 +#define DMC_PHY_CON29 0x78 +#define DMC_PHY_CON30 0x7C +#define DMC_PHY_CON31 0x80 +#define DMC_PHY_CON32 0x84 +#define DMC_PHY_CON33 0x88 +#define DMC_PHY_CON34 0x8C +#define DMC_PHY_CON35 0x90 +#define DMC_PHY_CON36 0x94 +#define DMC_PHY_CON37 0x98 +#define DMC_PHY_CON38 0x9C +#define DMC_PHY_CON39 0xA0 +#define DMC_PHY_CON40 0xA4 +#define DMC_PHY_CON41 0xA8 +#define DMC_PHY_CON42 0xAC +/* + * UART + */ + +#define UART0_OFFSET 0x00000 +#define UART1_OFFSET 0x10000 +#define UART2_OFFSET 0x20000 +#define UART3_OFFSET 0x30000 +#define UART4_OFFSET 0x40000 + +#if defined(CONFIG_SERIAL0) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART0_OFFSET) +#elif defined(CONFIG_SERIAL1) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART1_OFFSET) +#elif defined(CONFIG_SERIAL2) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART2_OFFSET) +#elif defined(CONFIG_SERIAL3) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART3_OFFSET) +#elif defined(CONFIG_SERIAL4) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART4_OFFSET) +#else +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART0_OFFSET) +#endif + +#define ULCON_OFFSET 0x00 +#define UCON_OFFSET 0x04 +#define UFCON_OFFSET 0x08 +#define UMCON_OFFSET 0x0C +#define UTRSTAT_OFFSET 0x10 +#define UERSTAT_OFFSET 0x14 +#define UFSTAT_OFFSET 0x18 +#define UMSTAT_OFFSET 0x1C +#define UTXH_OFFSET 0x20 +#define URXH_OFFSET 0x24 +#define UBRDIV_OFFSET 0x28 +#define UDIVSLOT_OFFSET 0x2C +#define UINTP_OFFSET 0x30 +#define UINTSP_OFFSET 0x34 +#define UINTM_OFFSET 0x38 +//#define UTRSTAT_TX_EMPTY BIT2 +//#define UTRSTAT_RX_READY BIT0 +#define UART_ERR_MASK 0xF + +/* + * HS MMC + */ +#define HSMMC_0_OFFSET 0x00000 +#define HSMMC_1_OFFSET 0x10000 +#define HSMMC_2_OFFSET 0x20000 +#define HSMMC_3_OFFSET 0x30000 +#define HSMMC_4_OFFSET 0x40000 + +#define ELFIN_HSMMC_0_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_0_OFFSET) +#define ELFIN_HSMMC_1_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_1_OFFSET) +#define ELFIN_HSMMC_2_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_2_OFFSET) +#define ELFIN_HSMMC_3_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_3_OFFSET) +#define ELFIN_HSMMC_4_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_4_OFFSET) + +#define HM_SYSAD (0x00) +#define HM_BLKSIZE (0x04) +#define HM_BLKCNT (0x06) +#define HM_ARGUMENT (0x08) +#define HM_TRNMOD (0x0c) +#define HM_CMDREG (0x0e) +#define HM_RSPREG0 (0x10) +#define HM_RSPREG1 (0x14) +#define HM_RSPREG2 (0x18) +#define HM_RSPREG3 (0x1c) +#define HM_BDATA (0x20) +#define HM_PRNSTS (0x24) +#define HM_HOSTCTL (0x28) +#define HM_PWRCON (0x29) +#define HM_BLKGAP (0x2a) +#define HM_WAKCON (0x2b) +#define HM_CLKCON (0x2c) +#define HM_TIMEOUTCON (0x2e) +#define HM_SWRST (0x2f) +#define HM_NORINTSTS (0x30) +#define HM_ERRINTSTS (0x32) +#define HM_NORINTSTSEN (0x34) +#define HM_ERRINTSTSEN (0x36) +#define HM_NORINTSIGEN (0x38) +#define HM_ERRINTSIGEN (0x3a) +#define HM_ACMD12ERRSTS (0x3c) +#define HM_CAPAREG (0x40) +#define HM_MAXCURR (0x48) +#define HM_CONTROL2 (0x80) +#define HM_CONTROL3 (0x84) +#define HM_CONTROL4 (0x8c) +#define HM_HCVER (0xfe) + +/* PENDING BIT */ +#define BIT_EINT0 (0x1) +#define BIT_EINT1 (0x1<<1) +#define BIT_EINT2 (0x1<<2) +#define BIT_EINT3 (0x1<<3) +#define BIT_EINT4_7 (0x1<<4) +#define BIT_EINT8_23 (0x1<<5) +#define BIT_BAT_FLT (0x1<<7) +#define BIT_TICK (0x1<<8) +#define BIT_WDT (0x1<<9) +#define BIT_TIMER0 (0x1<<10) +#define BIT_TIMER1 (0x1<<11) +#define BIT_TIMER2 (0x1<<12) +#define BIT_TIMER3 (0x1<<13) +#define BIT_TIMER4 (0x1<<14) +#define BIT_UART2 (0x1<<15) +#define BIT_LCD (0x1<<16) +#define BIT_DMA0 (0x1<<17) +#define BIT_DMA1 (0x1<<18) +#define BIT_DMA2 (0x1<<19) +#define BIT_DMA3 (0x1<<20) +#define BIT_SDI (0x1<<21) +#define BIT_SPI0 (0x1<<22) +#define BIT_UART1 (0x1<<23) +#define BIT_USBH (0x1<<26) +#define BIT_IIC (0x1<<27) +#define BIT_UART0 (0x1<<28) +#define BIT_SPI1 (0x1<<29) +#define BIT_RTC (0x1<<30) +#define BIT_ADC (0x1<<31) +#define BIT_ALLMSK (0xFFFFFFFF) + +#define PWMTIMER_BASE EXYNOS5250_PWMTIMER_BASE + +/* + * USBD3 SFR + */ +#define USBDEVICE3_LINK_BASE 0x12000000 +#define USBDEVICE3_PHYCTRL_BASE 0x12100000 + +//========================== +// Global Registers (Gxxxx) +//========================== +// Global Common Registers +#define rGSBUSCFG0 (USBDEVICE3_LINK_BASE + 0xc100) +#define rGSBUSCFG1 (USBDEVICE3_LINK_BASE + 0xc104) +#define rGTXTHRCFG (USBDEVICE3_LINK_BASE + 0xc108) +#define rGRXTHRCFG (USBDEVICE3_LINK_BASE + 0xc10c) +#define rGCTL (USBDEVICE3_LINK_BASE + 0xc110) +#define rGEVTEN (USBDEVICE3_LINK_BASE + 0xc114) +#define rGSTS (USBDEVICE3_LINK_BASE + 0xc118) +#define rGSNPSID (USBDEVICE3_LINK_BASE + 0xc120) +#define rGGPIO (USBDEVICE3_LINK_BASE + 0xc124) +#define rGUID (USBDEVICE3_LINK_BASE + 0xc128) +#define rGUCTL (USBDEVICE3_LINK_BASE + 0xc12c) +#define rGBUSERRADDR_LO (USBDEVICE3_LINK_BASE + 0xc130) +#define rGBUSERRADDR_HI (USBDEVICE3_LINK_BASE + 0xc134) + +// Global Port to USB Instance Mapping Registers +#define rGPRTBIMAP_LO (USBDEVICE3_LINK_BASE + 0xc138) +#define rGPRTBIMAP_HI (USBDEVICE3_LINK_BASE + 0xc13c) +#define rGPRTBIMAP_HS_LO (USBDEVICE3_LINK_BASE + 0xc180) +#define rGPRTBIMAP_HS_HI (USBDEVICE3_LINK_BASE + 0xc184) +#define rGPRTBIMAP_FS_LO (USBDEVICE3_LINK_BASE + 0xc188) +#define rGPRTBIMAP_FS_HI (USBDEVICE3_LINK_BASE + 0xc18c) + +// Global Hardware Parameter Registers +#define rGHWPARAMS0 (USBDEVICE3_LINK_BASE + 0xc140) // 0x20204000 @c510 +#define rGHWPARAMS1 (USBDEVICE3_LINK_BASE + 0xc144) // 0x0060c93b @c510 +#define rGHWPARAMS2 (USBDEVICE3_LINK_BASE + 0xc148) // 0x12345678 @c510 +#define rGHWPARAMS3 (USBDEVICE3_LINK_BASE + 0xc14c) // 0x10420085 @c510 +#define rGHWPARAMS4 (USBDEVICE3_LINK_BASE + 0xc150) // 0x48820004 @c510 +#define rGHWPARAMS5 (USBDEVICE3_LINK_BASE + 0xc154) // 0x04204108 @c510 +#define rGHWPARAMS6 (USBDEVICE3_LINK_BASE + 0xc158) // 0x04008020 @c510 +#define rGHWPARAMS7 (USBDEVICE3_LINK_BASE + 0xc15c) // 0x018516fe @c510 +#define rGHWPARAMS8 (USBDEVICE3_LINK_BASE + 0xc600) // 0x00000386 @c510 + +// Global Debug Registers +#define rGDBGFIFOSPACE (USBDEVICE3_LINK_BASE + 0xc160) +#define rGDBGLTSSM (USBDEVICE3_LINK_BASE + 0xc164) +#define rGDBGLSPMUX (USBDEVICE3_LINK_BASE + 0xc170) +#define rGDBGLSP (USBDEVICE3_LINK_BASE + 0xc174) +#define rGDBGEPINFO0 (USBDEVICE3_LINK_BASE + 0xc178) +#define rGDBGEPINFO1 (USBDEVICE3_LINK_BASE + 0xc17c) + +// Global PHY Registers +#define rGUSB2PHYCFG (USBDEVICE3_LINK_BASE + 0xc200) +#define rGUSB2I2CCTL (USBDEVICE3_LINK_BASE + 0xc240) +#define rGUSB2PHYACC (USBDEVICE3_LINK_BASE + 0xc280) +#define rGUSB3PIPECTL (USBDEVICE3_LINK_BASE + 0xc2c0) + +// Global FIFO Size Registers (0 <= num <= 15 @510) +#define rGTXFIFOSIZ(num) ((USBDEVICE3_LINK_BASE + 0xc300) + 0x04*num) +#define rGRXFIFOSIZ0 (USBDEVICE3_LINK_BASE + 0xc380) + +// Global Event Buffer Registers (DWC_USB3_DEVICE_NUM_INT = 1 @C510, GHWPARAMS1[20:15]) +#define rGEVNTADR_LO0 (USBDEVICE3_LINK_BASE + 0xc400) +#define rGEVNTADR_HI0 (USBDEVICE3_LINK_BASE + 0xc404) +#define rGEVNTSIZ0 (USBDEVICE3_LINK_BASE + 0xc408) +#define rGEVNTCOUNT0 (USBDEVICE3_LINK_BASE + 0xc40c) + +//========================== +// Device Registers (Dxxxx) +//========================== +// Device Common Registers +#define rDCFG (USBDEVICE3_LINK_BASE + 0xc700) +#define rDCTL (USBDEVICE3_LINK_BASE + 0xc704) +#define rDEVTEN (USBDEVICE3_LINK_BASE + 0xc708) +#define rDSTS (USBDEVICE3_LINK_BASE + 0xc70c) +#define rDGCMDPAR (USBDEVICE3_LINK_BASE + 0xc710) +#define rDGCMD (USBDEVICE3_LINK_BASE + 0xc714) +#define rDALEPENA (USBDEVICE3_LINK_BASE + 0xc720) + +// Device Endpoint Registers (0 <= ep <= 15) +#define rDOEPCMDPAR2(ep) ((USBDEVICE3_LINK_BASE + 0xc800) + 0x20*ep) +#define rDOEPCMDPAR1(ep) ((USBDEVICE3_LINK_BASE + 0xc804) + 0x20*ep) +#define rDOEPCMDPAR0(ep) ((USBDEVICE3_LINK_BASE + 0xc808) + 0x20*ep) +#define rDOEPCMD(ep) ((USBDEVICE3_LINK_BASE + 0xc80c) + 0x20*ep) + +#define rDIEPCMDPAR2(ep) ((USBDEVICE3_LINK_BASE + 0xc810) + 0x20*ep) +#define rDIEPCMDPAR1(ep) ((USBDEVICE3_LINK_BASE + 0xc814) + 0x20*ep) +#define rDIEPCMDPAR0(ep) ((USBDEVICE3_LINK_BASE + 0xc818) + 0x20*ep) +#define rDIEPCMD(ep) ((USBDEVICE3_LINK_BASE + 0xc81c) + 0x20*ep) + +//========================== +// USB DEVICE PHY CONTROL REGISTERS +//========================== +#define EXYNOS_PHY_LINKSYSTEM (USBDEVICE3_PHYCTRL_BASE + 0x04) +#define EXYNOS_PHY_UTMI (USBDEVICE3_PHYCTRL_BASE + 0x08) +#define EXYNOS_PHY_PIPE (USBDEVICE3_PHYCTRL_BASE + 0x0C) +#define EXYNOS_PHY_CLKPWR (USBDEVICE3_PHYCTRL_BASE + 0x10) +#define EXYNOS_PHY_REG0 (USBDEVICE3_PHYCTRL_BASE + 0x14) +#define EXYNOS_PHY_REG1 (USBDEVICE3_PHYCTRL_BASE + 0x18) +#define EXYNOS_PHY_PARAM0 (USBDEVICE3_PHYCTRL_BASE + 0x1C) +#define EXYNOS_PHY_PARAM1 (USBDEVICE3_PHYCTRL_BASE + 0x20) +#define EXYNOS_PHY_TERM (USBDEVICE3_PHYCTRL_BASE + 0x24) +#define EXYNOS_PHY_TEST (USBDEVICE3_PHYCTRL_BASE + 0x28) +#define EXYNOS_PHY_ADP (USBDEVICE3_PHYCTRL_BASE + 0x2C) +#define EXYNOS_PHY_BATCHG (USBDEVICE3_PHYCTRL_BASE + 0x30) +#define EXYNOS_PHY_RESUME (USBDEVICE3_PHYCTRL_BASE + 0x34) + +#endif /* _EXYNOS5250_CPU_H */ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Exynos5250_Evt1.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Exynos5250_Evt1.h new file mode 100755 index 000000000..e229a1377 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Platform/Exynos5250_Evt1.h @@ -0,0 +1,763 @@ +/* + * (C) Copyright 2012 Samsung Electronics Co. Ltd + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + */ + +#ifndef _EXYNOS5250_CPU_H +#define _EXYNOS5250_CPU_H + +/* EXYNOS5250 */ +#define EXYNOS5250_PRO_ID 0x10000000 +#define EXYNOS5250_SYSREG_BASE 0x10050000 +#define EXYNOS5250_POWER_BASE 0x10040000 +#define EXYNOS5250_CLOCK_BASE 0x10010000 +#define EXYNOS5250_SROM_BASE 0x12250000 +#define EXYNOS5250_HSMMC_BASE 0x12200000 +#define EXYNOS5250_PWMTIMER_BASE 0x12DD0000 +#define EXYNOS5250_INF_REG_BASE 0x10040800 +#define EXYNOS5250_TZPC_BASE 0x10100000 +#define EXYNOS5250_UART_BASE 0x12C00000 + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + + +#define __REG(x) (*(unsigned int *)(x)) + +/* + * CHIP ID + */ +#define CHIP_ID_BASE EXYNOS5250_PRO_ID +#define PRO_ID_OFFSET 0x0 +#define PRO_ID __REG(CHIP_ID_BASE+PRO_ID_OFFSET) +#define PRO_MAINREV ((PRO_ID >> 0x4) & 0x0f) +#define PRO_SUBREV (PRO_ID & 0x0f) +#define PRO_PKGINFO ((PRO_ID >> 0x8) & 0x0f) +#define SCP_TYPE 0x0 +#define POP_TYPE 0x2 + +/* + * SYSREG + */ +#define USB_CFG_OFFSET 0x230 +#define USB_CFG_REG (EXYNOS5250_SYSREG_BASE + USB_CFG_OFFSET) + +/* + * POWER + */ +#define ELFIN_POWER_BASE EXYNOS5250_POWER_BASE +#define OMR_OFFSET 0x0 +#define SW_RST_REG_OFFSET 0x400 +#define SW_RST_REG __REG(EXYNOS5250_POWER_BASE + SW_RST_REG_OFFSET) + +#define FSYS_ARM_CONFIGURATION_OFFSET 0x2200 +#define EFNAND_PHY_CONTROL_OFFSET 0x070C +#define SATA_PHY_CONTROL_OFFSET 0x0724 + +#define INF_REG_BASE EXYNOS5250_INF_REG_BASE + +#define INF_REG0_OFFSET 0x00 +#define INF_REG1_OFFSET 0x04 +#define INF_REG2_OFFSET 0x08 +#define INF_REG3_OFFSET 0x0C +#define INF_REG4_OFFSET 0x10 +#define INF_REG5_OFFSET 0x14 +#define INF_REG6_OFFSET 0x18 +#define INF_REG7_OFFSET 0x1C + +#define INF_REG0_REG __REG(INF_REG_BASE+INF_REG0_OFFSET) +#define INF_REG1_REG __REG(INF_REG_BASE+INF_REG1_OFFSET) +#define INF_REG2_REG __REG(INF_REG_BASE+INF_REG2_OFFSET) +#define INF_REG3_REG __REG(INF_REG_BASE+INF_REG3_OFFSET) +#define INF_REG4_REG __REG(INF_REG_BASE+INF_REG4_OFFSET) +#define INF_REG5_REG __REG(INF_REG_BASE+INF_REG5_OFFSET) +#define INF_REG6_REG __REG(INF_REG_BASE+INF_REG6_OFFSET) +#define INF_REG7_REG __REG(INF_REG_BASE+INF_REG7_OFFSET) + +#define USB_DEVICE_PHY_CONTROL_OFFSET 0x0704 +#define USB_PHY_CONTROL_OFFSET 0x0708 +#define USB_DEVICE_PHY_CONTROL (EXYNOS5250_POWER_BASE+USB_DEVICE_PHY_CONTROL_OFFSET) +#define USB_PHY_CONTROL (EXYNOS5250_POWER_BASE+USB_PHY_CONTROL_OFFSET) + +/* Define Mode */ +#define S5P_CHECK_SLEEP 0x00000BAD +#define S5P_CHECK_DIDLE 0xBAD00000 +#define S5P_CHECK_LPA 0xABAD0000 + +/* + * CLOCK + */ +#define ELFIN_CLOCK_BASE EXYNOS5250_CLOCK_BASE + +#define APLL_LOCK_OFFSET 0x00000 +#define APLL_CON0_OFFSET 0x00100 +#define APLL_CON1_OFFSET 0x00104 +#define CLK_SRC_CPU_OFFSET 0x00200 +#define CLK_MUX_STAT_CPU_OFFSET 0x00400 +#define CLK_DIV_CPU0_OFFSET 0x00500 +#define CLK_DIV_CPU1_OFFSET 0x00504 +#define CLK_DIV_STAT_CPU0_OFFSET 0x00600 +#define CLK_DIV_STAT_CPU1_OFFSET 0x00604 +#define CLK_GATE_SCLK_CPU_OFFSET 0x00800 +#define CLKOUT_CMU_CPU_OFFSET 0x00A00 +#define CLKOUT_CMU_CPU_DIV_STAT_OFFSET 0x00A04 +#define ARMCLK_STOPCTRL_OFFSET 0x01000 +#define PARITYFAIL_STATUS_OFFSET 0x01010 +#define PARITYFAIL_CLEAR_OFFSET 0x01014 +#define PWR_CTRL_OFFSET 0x01020 +#define PWR_CTRL2_OFFSET 0x01024 +#define APLL_CON0_L8_OFFSET 0x01100 +#define APLL_CON0_L7_OFFSET 0x01104 +#define APLL_CON0_L6_OFFSET 0x01108 +#define APLL_CON0_L5_OFFSET 0x0110C +#define APLL_CON0_L4_OFFSET 0x01110 +#define APLL_CON0_L3_OFFSET 0x01114 +#define APLL_CON0_L2_OFFSET 0x01118 +#define APLL_CON0_L1_OFFSET 0x0111C +#define IEM_CONTROL_OFFSET 0x01120 +#define APLL_CON1_L8_OFFSET 0x01200 +#define APLL_CON1_L7_OFFSET 0x01204 +#define APLL_CON1_L6_OFFSET 0x01208 +#define APLL_CON1_L5_OFFSET 0x0120C +#define APLL_CON1_L4_OFFSET 0x01210 +#define APLL_CON1_L3_OFFSET 0x01214 +#define APLL_CON1_L2_OFFSET 0x01218 +#define APLL_CON1_L1_OFFSET 0x0121C +#define CLKDIV_IEM_L8_OFFSET 0x01300 +#define CLKDIV_IEM_L7_OFFSET 0x01304 +#define CLKDIV_IEM_L6_OFFSET 0x01308 +#define CLKDIV_IEM_L5_OFFSET 0x0130C +#define CLKDIV_IEM_L4_OFFSET 0x01310 +#define CLKDIV_IEM_L3_OFFSET 0x01314 +#define CLKDIV_IEM_L2_OFFSET 0x01318 +#define CLKDIV_IEM_L1_OFFSET 0x0131C +#define MPLL_LOCK_OFFSET 0x04000 +#define MPLL_CON0_OFFSET 0x04100 +#define MPLL_CON1_OFFSET 0x04104 +#define CLK_SRC_CORE0_OFFSET 0x04200 +#define CLK_SRC_CORE1_OFFSET 0x04204 +#define CLK_SRC_MASK_CORE0_OFFSET 0x04300 +#define CLK_MUX_STAT_CORE1_OFFSET 0x04404 +#define CLK_DIV_CORE0_OFFSET 0x04500 +#define CLK_DIV_CORE1_OFFSET 0x04504 +#define CLK_DIV_SYSRGT_OFFSET 0x04508 +#define CLK_DIV_STAT_CORE0_OFFSET 0x04600 +#define CLK_DIV_STAT_CORE1_OFFSET 0x04604 +#define CLK_DIV_STAT_SYSRGT_OFFSET 0x04608 +#define CLK_GATE_IP_CORE_OFFSET 0x04900 +#define CLK_GATE_IP_SYSRGT_OFFSET 0x04904 +#define C2C_MONITOR_OFFSET 0x04910 +#define CLKOUT_CMU_CORE_OFFSET 0x04A00 +#define CLKOUT_CMU_CORE_DIV_STAT_OFFSET 0x04A04 +#define DCGIDX_MAP0_OFFSET 0x05000 +#define DCGIDX_MAP1_OFFSET 0x05004 +#define DCGIDX_MAP2_OFFSET 0x05008 +#define DCGPERF_MAP0_OFFSET 0x05020 +#define DCGPERF_MAP1_OFFSET 0x05024 +#define DVCIDX_MAP_OFFSET 0x05040 +#define FREQ_CPU_OFFSET 0x05060 +#define FREQ_DPM_OFFSET 0x05064 +#define DVSEMCLK_EN_OFFSET 0x05080 +#define MAXPERF_OFFSET 0x05084 +#define C2C_CONFIG_OFFSET 0x06000 +#define CLK_DIV_ACP_OFFSET 0x08500 +#define CLK_DIV_STAT_ACP_OFFSET 0x08600 +#define CLK_GATE_IP_ACP_OFFSET 0x08800 +#define CLK_DIV_SYSLFT_OFFSET 0x08900 +#define CLK_DIV_STAT_SYSLFT_OFFSET 0x08910 +#define CLK_GATE_IP_SYSLFT_OFFSET 0x08930 +#define CLKOUT_CMU_ACP_OFFSET 0x08A00 +#define CLKOUT_CMU_ACP_DIV_STAT_OFFSET 0x08A04 +#define UFMC_CONFIG_OFFSET 0x08A10 +#define CLK_DIV_ISP0_OFFSET 0x0C300 +#define CLK_DIV_ISP1_OFFSET 0x0C304 +#define CLK_DIV_ISP2_OFFSET 0x0C308 +#define CLK_DIV_STAT_ISP0_OFFSET 0x0C400 +#define CLK_DIV_STAT_ISP1_OFFSET 0x0C404 +#define CLK_DIV_STAT_ISP2_OFFSET 0x0C408 +#define CLK_GATE_IP_ISP0_OFFSET 0x0C800 +#define CLK_GATE_IP_ISP1_OFFSET 0x0C804 +#define CLK_GATE_SCLK_ISP_OFFSET 0x0C900 +#define MCUISP_PWR_CTRL_OFFSET 0x0C910 +#define CLKOUT_CMU_ISP_OFFSET 0x0CA00 +#define CLKOUT_CMU_ISP_DIV_STAT_OFFSET 0x0CA04 +#define CPLL_LOCK_OFFSET 0x10020 +#define EPLL_LOCK_OFFSET 0x10030 +#define VPLL_LOCK_OFFSET 0x10040 +#define GPLL_LOCK_OFFSET 0x10050 +#define CPLL_CON0_OFFSET 0x10120 +#define CPLL_CON1_OFFSET 0x10124 +#define EPLL_CON0_OFFSET 0x10130 +#define EPLL_CON1_OFFSET 0x10134 +#define EPLL_CON2_OFFSET 0x10138 +#define VPLL_CON0_OFFSET 0x10140 +#define VPLL_CON1_OFFSET 0x10144 +#define VPLL_CON2_OFFSET 0x10148 +#define GPLL_CON0_OFFSET 0x10150 +#define GPLL_CON1_OFFSET 0x10154 +#define CLK_SRC_TOP0_OFFSET 0x10210 +#define CLK_SRC_TOP1_OFFSET 0x10214 +#define CLK_SRC_TOP2_OFFSET 0x10218 +#define CLK_SRC_TOP3_OFFSET 0x1021C +#define CLK_SRC_GSCL_OFFSET 0x10220 +#define CLK_SRC_DISP1_0_OFFSET 0x1022C +#define CLK_SRC_MAU_OFFSET 0x10240 +#define CLK_SRC_FSYS_OFFSET 0x10244 +#define CLK_SRC_GEN_OFFSET 0x10248 +#define CLK_SRC_PERIC0_OFFSET 0x10250 +#define CLK_SRC_PERIC1_OFFSET 0x10254 +#define SCLK_SRC_ISP_OFFSET 0x10270 +#define CLK_SRC_MASK_TOP_OFFSET 0x10310 +#define CLK_SRC_MASK_GSCL_OFFSET 0x10320 +#define CLK_SRC_MASK_DISP1_0_OFFSET 0x1032C +#define CLK_SRC_MASK_DISP1_1_OFFSET 0x10330 +#define CLK_SRC_MASK_MAU_OFFSET 0x10334 +#define CLK_SRC_MASK_FSYS_OFFSET 0x10340 +#define CLK_SRC_MASK_GEN_OFFSET 0x10344 +#define CLK_SRC_MASK_PERIC0_OFFSET 0x10350 +#define CLK_SRC_MASK_PERIC1_OFFSET 0x10354 +#define SCLK_SRC_MASK_ISP_OFFSET 0x10370 +#define CLK_MUX_STAT_TOP0_OFFSET 0x10410 +#define CLK_MUX_STAT_TOP1_OFFSET 0x10414 +#define CLK_MUX_STAT_TOP2_OFFSET 0x10418 +#define CLK_MUX_STAT_TOP3_OFFSET 0x1041C +#define CLK_DIV_TOP0_OFFSET 0x10510 +#define CLK_DIV_TOP1_OFFSET 0x10514 +#define CLK_DIV_GSCL_OFFSET 0x10520 +#define CLK_DIV_DISP1_0_OFFSET 0x1052C +#define CLK_DIV_GEN_OFFSET 0x1053C +#define CLK_DIV_MAU_OFFSET 0x10544 +#define CLK_DIV_FSYS0_OFFSET 0x10548 +#define CLK_DIV_FSYS1_OFFSET 0x1054C +#define CLK_DIV_FSYS2_OFFSET 0x10550 +#define CLK_DIV_PERIC0_OFFSET 0x10558 +#define CLK_DIV_PERIC1_OFFSET 0x1055C +#define CLK_DIV_PERIC2_OFFSET 0x10560 +#define CLK_DIV_PERIC3_OFFSET 0x10564 +#define CLK_DIV_PERIC4_OFFSET 0x10568 +#define CLK_DIV_PERIC5_OFFSET 0x1056C +#define SCLK_DIV_ISP_OFFSET 0x10580 +#define CLKDIV2_RATIO0_OFFSET 0x10590 +#define CLKDIV2_RATIO1_OFFSET 0x10594 +#define CLKDIV4_RATIO_OFFSET 0x105A0 +#define CLK_DIV_STAT_TOP0_OFFSET 0x10610 +#define CLK_DIV_STAT_TOP1_OFFSET 0x10614 +#define CLK_DIV_STAT_GSCL_OFFSET 0x10620 +#define CLK_DIV_STAT_DISP1_0_OFFSET 0x1062C +#define CLK_DIV_STAT_GEN_OFFSET 0x1063C +#define CLK_DIV_STAT_MAU_OFFSET 0x10644 +#define CLK_DIV_STAT_FSYS0_OFFSET 0x10648 +#define CLK_DIV_STAT_FSYS1_OFFSET 0x1064C +#define CLK_DIV_STAT_FSYS2_OFFSET 0x10650 +#define CLK_DIV_STAT_PERIC0_OFFSET 0x10658 +#define CLK_DIV_STAT_PERIC1_OFFSET 0x1065C +#define CLK_DIV_STAT_PERIC2_OFFSET 0x10660 +#define CLK_DIV_STAT_PERIC3_OFFSET 0x10664 +#define CLK_DIV_STAT_PERIC4_OFFSET 0x10668 +#define CLK_DIV_STAT_PERIC5_OFFSET 0x1066C +#define SCLK_DIV_STAT_ISP_OFFSET 0x10680 +#define CLKDIV2_STAT0_OFFSET 0x10690 +#define CLKDIV2_STAT1_OFFSET 0x10694 +#define CLKDIV4_STAT_OFFSET 0x106A0 +#define CLK_GATE_TOP_SCLK_DISP1_OFFSET 0x10828 +#define CLK_GATE_TOP_SCLK_GEN_OFFSET 0x1082C +#define CLK_GATE_TOP_SCLK_MAU_OFFSET 0x1083C +#define CLK_GATE_TOP_SCLK_FSYS_OFFSET 0x10840 +#define CLK_GATE_TOP_SCLK_PERIC_OFFSET 0x10850 +#define CLK_GATE_TOP_SCLK_ISP_OFFSET 0x10870 +#define CLK_GATE_IP_GSCL_OFFSET 0x10920 +#define CLK_GATE_IP_DISP1_OFFSET 0x10928 +#define CLK_GATE_IP_MFC_OFFSET 0x1092C +#define CLK_GATE_IP_G3D_OFFSET 0x10930 +#define CLK_GATE_IP_GEN_OFFSET 0x10934 +#define CLK_GATE_IP_FSYS_OFFSET 0x10944 +#define CLK_GATE_IP_PERIC_OFFSET 0x10950 +#define CLK_GATE_IP_PERIS_OFFSET 0x10960 +#define CLK_GATE_BLOCK_OFFSET 0x10980 +#define MCUIOP_PWR_CTRL_OFFSET 0x109A0 +#define CLKOUT_CMU_TOP_OFFSET 0x10A00 +#define CLKOUT_CMU_TOP_DIV_STAT_OFFSET 0x10A04 +#define CLK_SRC_LEX_OFFSET 0x14200 +#define CLK_MUX_STAT_LEX_OFFSET 0x14400 +#define CLK_DIV_LEX_OFFSET 0x14500 +#define CLK_DIV_STAT_LEX_OFFSET 0x14600 +#define CLK_GATE_IP_LEX_OFFSET 0x14800 +#define CLKOUT_CMU_LEX_OFFSET 0x14A00 +#define CLKOUT_CMU_LEX_DIV_STAT_OFFSET 0x14A04 +#define CLK_DIV_R0X_OFFSET 0x18500 +#define CLK_DIV_STAT_R0X_OFFSET 0x18600 +#define CLK_GATE_IP_R0X_OFFSET 0x18800 +#define CLKOUT_CMU_R0X_OFFSET 0x18A00 +#define CLKOUT_CMU_R0X_DIV_STAT_OFFSET 0x18A04 +#define CLK_DIV_R1X_OFFSET 0x1C500 +#define CLK_DIV_STAT_R1X_OFFSET 0x1C600 +#define CLK_GATE_IP_R1X_OFFSET 0x1C800 +#define CLKOUT_CMU_R1X_OFFSET 0x1CA00 +#define CLKOUT_CMU_R1X_DIV_STAT_OFFSET 0x1CA04 +#define BPLL_LOCK_OFFSET 0x20010 +#define BPLL_CON0_OFFSET 0x20110 +#define BPLL_CON1_OFFSET 0x20114 +#define CLK_SRC_CDREX_OFFSET 0x20200 +#define CLK_MUX_STAT_CDREX_OFFSET 0x20400 +#define CLK_DIV_CDREX_OFFSET 0x20500 +#define CLK_DIV_STAT_CDREX_OFFSET 0x20600 +#define CLK_GATE_IP_CDREX_OFFSET 0x20900 +#define DMC_FREQ_CTRL_OFFSET 0x20914 +#define DREX2_PAUSE_OFFSET 0x2091C +#define CLKOUT_CMU_CDREX_OFFSET 0x20A00 +#define CLKOUT_CMU_CDREX_DIV_STAT_OFFSET 0x20A04 +#define LPDDR3PHY_CTRL 0x20A10 +#define LPDDR3PHY_CTRL_CON0 0x20A14 +#define LPDDR3PHY_CTRL_CON1 0x20A18 +#define LPDDR3PHY_CTRL_CON2 0x20A1C +#define LPDDR3PHY_CTRL_CON3 0x20A20 +#define PLL_DIV2_SEL_OFFSET 0x20A24 + +#define CLK_SRC_FSYS __REG(ELFIN_CLOCK_BASE+CLK_SRC_FSYS_OFFSET) +#define CLK_DIV_FSYS0 __REG(ELFIN_CLOCK_BASE+CLK_DIV_FSYS0_OFFSET) +#define CLK_DIV_FSYS1 __REG(ELFIN_CLOCK_BASE+CLK_DIV_FSYS1_OFFSET) +#define CLK_DIV_FSYS2 __REG(ELFIN_CLOCK_BASE+CLK_DIV_FSYS2_OFFSET) +#define APLL_CON0_REG __REG(ELFIN_CLOCK_BASE+APLL_CON0_OFFSET) +#define MPLL_CON0_REG __REG(ELFIN_CLOCK_BASE+MPLL_CON0_OFFSET) +#define EPLL_CON0_REG __REG(ELFIN_CLOCK_BASE+EPLL_CON0_OFFSET) +#define VPLL_CON0_REG __REG(ELFIN_CLOCK_BASE+VPLL_CON0_OFFSET) + +/* + * TZPC + */ +#define TZPC0_OFFSET 0x00000 +#define TZPC1_OFFSET 0x10000 +#define TZPC2_OFFSET 0x20000 +#define TZPC3_OFFSET 0x30000 +#define TZPC4_OFFSET 0x40000 +#define TZPC5_OFFSET 0x50000 +#define TZPC6_OFFSET 0x60000 +#define TZPC7_OFFSET 0x70000 +#define TZPC8_OFFSET 0x80000 +#define TZPC9_OFFSET 0x90000 + +#define ELFIN_TZPC0_BASE (EXYNOS5250_TZPC_BASE + TZPC0_OFFSET) +#define ELFIN_TZPC1_BASE (EXYNOS5250_TZPC_BASE + TZPC1_OFFSET) +#define ELFIN_TZPC2_BASE (EXYNOS5250_TZPC_BASE + TZPC2_OFFSET) +#define ELFIN_TZPC3_BASE (EXYNOS5250_TZPC_BASE + TZPC3_OFFSET) +#define ELFIN_TZPC4_BASE (EXYNOS5250_TZPC_BASE + TZPC4_OFFSET) +#define ELFIN_TZPC5_BASE (EXYNOS5250_TZPC_BASE + TZPC5_OFFSET) +#define ELFIN_TZPC6_BASE (EXYNOS5250_TZPC_BASE + TZPC6_OFFSET) +#define ELFIN_TZPC7_BASE (EXYNOS5250_TZPC_BASE + TZPC7_OFFSET) +#define ELFIN_TZPC8_BASE (EXYNOS5250_TZPC_BASE + TZPC8_OFFSET) +#define ELFIN_TZPC9_BASE (EXYNOS5250_TZPC_BASE + TZPC9_OFFSET) + +#define TZPC_DECPROT0SET_OFFSET 0x804 +#define TZPC_DECPROT1SET_OFFSET 0x810 +#define TZPC_DECPROT2SET_OFFSET 0x81C +#define TZPC_DECPROT3SET_OFFSET 0x828 + +/* + * Memory controller + */ +#define ELFIN_SROM_BASE EXYNOS5250_SROM_BASE + +#define SROM_BW_REG __REG(ELFIN_SROM_BASE+0x0) +#define SROM_BC0_REG __REG(ELFIN_SROM_BASE+0x4) +#define SROM_BC1_REG __REG(ELFIN_SROM_BASE+0x8) +#define SROM_BC2_REG __REG(ELFIN_SROM_BASE+0xC) +#define SROM_BC3_REG __REG(ELFIN_SROM_BASE+0x10) + +/* + * SDRAM Controller + */ + +/* DMC control register */ +#define DMC_CTRL_BASE 0x10DD0000 + +#define DMC_CONCONTROL 0x00 +#define DMC_MEMCONTROL 0x04 +#define DMC_MEMCONFIG0 0x08 +#define DMC_MEMCONFIG1 0x0C +#define DMC_DIRECTCMD 0x10 +#define DMC_PRECHCONFIG 0x14 +#define DMC_PHYCONTROL0 0x18 +#define DMC_PWRDNCONFIG 0x28 +#define DMC_TIMINGPZQ 0x2C +#define DMC_TIMINGAREF 0x30 +#define DMC_TIMINGROW 0x34 +#define DMC_TIMINGDATA 0x38 +#define DMC_TIMINGPOWER 0x3C +#define DMC_PHYSTATUS 0x40 +#define DMC_CHIPSTATUS_CH0 0x48 +#define DMC_CHIPSTATUS_CH1 0x4C +#define DMC_MRSTATUS 0x54 +#define DMC_QOSCONTROL0 0x60 +#define DMC_QOSCONTROL1 0x68 +#define DMC_QOSCONTROL2 0x70 +#define DMC_QOSCONTROL3 0x78 +#define DMC_QOSCONTROL4 0x80 +#define DMC_QOSCONTROL5 0x88 +#define DMC_QOSCONTROL6 0x90 +#define DMC_QOSCONTROL7 0x98 +#define DMC_QOSCONTROL8 0xA0 +#define DMC_QOSCONTROL9 0xA8 +#define DMC_QOSCONTROL10 0xB0 +#define DMC_QOSCONTROL11 0xB8 +#define DMC_QOSCONTROL12 0xC0 +#define DMC_QOSCONTROL13 0xC8 +#define DMC_QOSCONTROL14 0xD0 +#define DMC_QOSCONTROL15 0xD8 +#define DMC_IVCONTROL 0xF0 +#define DMC_WRTRA_CONFIG 0xF4 +#define DMC_RDLVL_CONFIG 0xF8 +#define DMC_BRBRSVCONTROL 0x0100 +#define DMC_BRBRSVCONFIG 0x0104 +#define DMC_BRBQOSCONFIG 0x0108 +#define DMC_MEMBASECONFIG0 0x010C +#define DMC_MEMBASECONFIG1 0x0110 +#define DMC_WRLVLCONFIG0 0x0120 +#define DMC_WRLVLCONFIG1 0x0124 +#define DMC_WRLVLSTATUS 0x0128 +#define DMC_PEREVCONTROL 0x0130 +#define DMC_PEREV0CONFIG 0x0134 +#define DMC_PEREV1CONFIG 0x0138 +#define DMC_PEREV2CONFIG 0x013C +#define DMC_PEREV3CONFIG 0x0140 +#define DMC_CTRL_IO_RDATA_CH0 0x0150 +#define DMC_CTRL_IO_RDATA_CH1 0x0154 +#define DMC_CACAL_CONFIG0 0x0160 +#define DMC_CACAL_CONFIG1 0x0164 +#define DMC_CACAL_STATUS 0x0168 +#define DMC_PMNC_PPC 0xE000 +#define DMC_CNTENS_PPC 0xE010 +#define DMC_CNTENC_PPC 0xE020 +#define DMC_INTENS_PPC 0xE030 +#define DMC_INTENC_PPC 0xE040 +#define DMC_FLAG_PPC 0xE050 +#define DMC_CCNT_PPC 0xE100 +#define DMC_PMCNT0_PPC 0xE110 +#define DMC_PMCNT1_PPC 0xE120 +#define DMC_PMCNT2_PPC 0xE130 +#define DMC_PMCNT3_PPC 0xE140 + +/* PHY Control Register */ +#define PHY0_CTRL_BASE 0x10C00000 +#define PHY1_CTRL_BASE 0x10C10000 + +#define DMC_PHY_CON0 0x00 +#define DMC_PHY_CON1 0x04 +#define DMC_PHY_CON2 0x08 +#define DMC_PHY_CON3 0x0C +#define DMC_PHY_CON4 0x10 +#define DMC_PHY_CON6 0x18 +#define DMC_PHY_CON8 0x20 +#define DMC_PHY_CON10 0x28 +#define DMC_PHY_CON11 0x2C +#define DMC_PHY_CON12 0x30 +#define DMC_PHY_CON13 0x34 +#define DMC_PHY_CON14 0x38 +#define DMC_PHY_CON15 0x3C +#define DMC_PHY_CON16 0x40 +#define DMC_PHY_CON17 0x48 +#define DMC_PHY_CON18 0x4C +#define DMC_PHY_CON19 0x50 +#define DMC_PHY_CON20 0x54 +#define DMC_PHY_CON21 0x58 +#define DMC_PHY_CON22 0x5C +#define DMC_PHY_CON23 0x60 +#define DMC_PHY_CON24 0x64 +#define DMC_PHY_CON25 0x68 +#define DMC_PHY_CON26 0x6C +#define DMC_PHY_CON27 0x70 +#define DMC_PHY_CON28 0x74 +#define DMC_PHY_CON29 0x78 +#define DMC_PHY_CON30 0x7C +#define DMC_PHY_CON31 0x80 +#define DMC_PHY_CON32 0x84 +#define DMC_PHY_CON33 0x88 +#define DMC_PHY_CON34 0x8C +#define DMC_PHY_CON35 0x90 +#define DMC_PHY_CON36 0x94 +#define DMC_PHY_CON37 0x98 +#define DMC_PHY_CON38 0x9C +#define DMC_PHY_CON39 0xA0 +#define DMC_PHY_CON40 0xA4 +#define DMC_PHY_CON41 0xA8 +#define DMC_PHY_CON42 0xAC + + +/* + * FBM + */ +#define DDR_R1_FBM_BASE 0x10c30000 +#define DDR_R0_FBM_BASE 0x10dc0000 + +#define FBM_MODESEL0 0x0 +#define FBM_THRESHOLDSEL0 0x40 + +/* + * UART + */ + +#define UART0_OFFSET 0x00000 +#define UART1_OFFSET 0x10000 +#define UART2_OFFSET 0x20000 +#define UART3_OFFSET 0x30000 + +#if defined(CONFIG_SERIAL0) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART0_OFFSET) +#elif defined(CONFIG_SERIAL1) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART1_OFFSET) +#elif defined(CONFIG_SERIAL2) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART2_OFFSET) +#elif defined(CONFIG_SERIAL3) +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART3_OFFSET) +#else +#define UART_CONSOLE_BASE (EXYNOS5250_UART_BASE + UART0_OFFSET) +#endif + +#define ULCON_OFFSET 0x00 +#define UCON_OFFSET 0x04 +#define UFCON_OFFSET 0x08 +#define UMCON_OFFSET 0x0C +#define UTRSTAT_OFFSET 0x10 +#define UERSTAT_OFFSET 0x14 +#define UFSTAT_OFFSET 0x18 +#define UMSTAT_OFFSET 0x1C +#define UTXH_OFFSET 0x20 +#define URXH_OFFSET 0x24 +#define UBRDIV_OFFSET 0x28 +#define UDIVSLOT_OFFSET 0x2C +#define UINTP_OFFSET 0x30 +#define UINTSP_OFFSET 0x34 +#define UINTM_OFFSET 0x38 +//#define UTRSTAT_TX_EMPTY BIT2 +//#define UTRSTAT_RX_READY BIT0 +#define UART_ERR_MASK 0xF + +/* + * HS MMC + */ +#define HSMMC_0_OFFSET 0x00000 +#define HSMMC_1_OFFSET 0x10000 +#define HSMMC_2_OFFSET 0x20000 +#define HSMMC_3_OFFSET 0x30000 + +#define ELFIN_HSMMC_0_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_0_OFFSET) +#define ELFIN_HSMMC_1_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_1_OFFSET) +#define ELFIN_HSMMC_2_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_2_OFFSET) +#define ELFIN_HSMMC_3_BASE (EXYNOS5250_HSMMC_BASE + HSMMC_3_OFFSET) + +#define HM_SYSAD (0x00) +#define HM_BLKSIZE (0x04) +#define HM_BLKCNT (0x06) +#define HM_ARGUMENT (0x08) +#define HM_TRNMOD (0x0c) +#define HM_CMDREG (0x0e) +#define HM_RSPREG0 (0x10) +#define HM_RSPREG1 (0x14) +#define HM_RSPREG2 (0x18) +#define HM_RSPREG3 (0x1c) +#define HM_BDATA (0x20) +#define HM_PRNSTS (0x24) +#define HM_HOSTCTL (0x28) +#define HM_PWRCON (0x29) +#define HM_BLKGAP (0x2a) +#define HM_WAKCON (0x2b) +#define HM_CLKCON (0x2c) +#define HM_TIMEOUTCON (0x2e) +#define HM_SWRST (0x2f) +#define HM_NORINTSTS (0x30) +#define HM_ERRINTSTS (0x32) +#define HM_NORINTSTSEN (0x34) +#define HM_ERRINTSTSEN (0x36) +#define HM_NORINTSIGEN (0x38) +#define HM_ERRINTSIGEN (0x3a) +#define HM_ACMD12ERRSTS (0x3c) +#define HM_CAPAREG (0x40) +#define HM_MAXCURR (0x48) +#define HM_CONTROL2 (0x80) +#define HM_CONTROL3 (0x84) +#define HM_CONTROL4 (0x8c) +#define HM_HCVER (0xfe) + +/* PENDING BIT */ +#define BIT_EINT0 (0x1) +#define BIT_EINT1 (0x1<<1) +#define BIT_EINT2 (0x1<<2) +#define BIT_EINT3 (0x1<<3) +#define BIT_EINT4_7 (0x1<<4) +#define BIT_EINT8_23 (0x1<<5) +#define BIT_BAT_FLT (0x1<<7) +#define BIT_TICK (0x1<<8) +#define BIT_WDT (0x1<<9) +#define BIT_TIMER0 (0x1<<10) +#define BIT_TIMER1 (0x1<<11) +#define BIT_TIMER2 (0x1<<12) +#define BIT_TIMER3 (0x1<<13) +#define BIT_TIMER4 (0x1<<14) +#define BIT_UART2 (0x1<<15) +#define BIT_LCD (0x1<<16) +#define BIT_DMA0 (0x1<<17) +#define BIT_DMA1 (0x1<<18) +#define BIT_DMA2 (0x1<<19) +#define BIT_DMA3 (0x1<<20) +#define BIT_SDI (0x1<<21) +#define BIT_SPI0 (0x1<<22) +#define BIT_UART1 (0x1<<23) +#define BIT_USBH (0x1<<26) +#define BIT_IIC (0x1<<27) +#define BIT_UART0 (0x1<<28) +#define BIT_SPI1 (0x1<<29) +#define BIT_RTC (0x1<<30) +#define BIT_ADC (0x1<<31) +#define BIT_ALLMSK (0xFFFFFFFF) + +#define PWMTIMER_BASE EXYNOS5250_PWMTIMER_BASE + +/* + * USBD3 SFR + */ +#define USBDEVICE3_LINK_BASE 0x12000000 +#define USBDEVICE3_PHYCTRL_BASE 0x12100000 + +//========================== +// Global Registers (Gxxxx) +//========================== +// Global Common Registers +#define rGSBUSCFG0 (USBDEVICE3_LINK_BASE + 0xc100) +#define rGSBUSCFG1 (USBDEVICE3_LINK_BASE + 0xc104) +#define rGTXTHRCFG (USBDEVICE3_LINK_BASE + 0xc108) +#define rGRXTHRCFG (USBDEVICE3_LINK_BASE + 0xc10c) +#define rGCTL (USBDEVICE3_LINK_BASE + 0xc110) +#define rGEVTEN (USBDEVICE3_LINK_BASE + 0xc114) +#define rGSTS (USBDEVICE3_LINK_BASE + 0xc118) +#define rGSNPSID (USBDEVICE3_LINK_BASE + 0xc120) +#define rGGPIO (USBDEVICE3_LINK_BASE + 0xc124) +#define rGUID (USBDEVICE3_LINK_BASE + 0xc128) +#define rGUCTL (USBDEVICE3_LINK_BASE + 0xc12c) +#define rGBUSERRADDR_LO (USBDEVICE3_LINK_BASE + 0xc130) +#define rGBUSERRADDR_HI (USBDEVICE3_LINK_BASE + 0xc134) + +// Global Port to USB Instance Mapping Registers +#define rGPRTBIMAP_LO (USBDEVICE3_LINK_BASE + 0xc138) +#define rGPRTBIMAP_HI (USBDEVICE3_LINK_BASE + 0xc13c) +#define rGPRTBIMAP_HS_LO (USBDEVICE3_LINK_BASE + 0xc180) +#define rGPRTBIMAP_HS_HI (USBDEVICE3_LINK_BASE + 0xc184) +#define rGPRTBIMAP_FS_LO (USBDEVICE3_LINK_BASE + 0xc188) +#define rGPRTBIMAP_FS_HI (USBDEVICE3_LINK_BASE + 0xc18c) + +// Global Hardware Parameter Registers +#define rGHWPARAMS0 (USBDEVICE3_LINK_BASE + 0xc140) // 0x20204000 @c510 +#define rGHWPARAMS1 (USBDEVICE3_LINK_BASE + 0xc144) // 0x0060c93b @c510 +#define rGHWPARAMS2 (USBDEVICE3_LINK_BASE + 0xc148) // 0x12345678 @c510 +#define rGHWPARAMS3 (USBDEVICE3_LINK_BASE + 0xc14c) // 0x10420085 @c510 +#define rGHWPARAMS4 (USBDEVICE3_LINK_BASE + 0xc150) // 0x48820004 @c510 +#define rGHWPARAMS5 (USBDEVICE3_LINK_BASE + 0xc154) // 0x04204108 @c510 +#define rGHWPARAMS6 (USBDEVICE3_LINK_BASE + 0xc158) // 0x04008020 @c510 +#define rGHWPARAMS7 (USBDEVICE3_LINK_BASE + 0xc15c) // 0x018516fe @c510 +#define rGHWPARAMS8 (USBDEVICE3_LINK_BASE + 0xc600) // 0x00000386 @c510 + +// Global Debug Registers +#define rGDBGFIFOSPACE (USBDEVICE3_LINK_BASE + 0xc160) +#define rGDBGLTSSM (USBDEVICE3_LINK_BASE + 0xc164) +#define rGDBGLSPMUX (USBDEVICE3_LINK_BASE + 0xc170) +#define rGDBGLSP (USBDEVICE3_LINK_BASE + 0xc174) +#define rGDBGEPINFO0 (USBDEVICE3_LINK_BASE + 0xc178) +#define rGDBGEPINFO1 (USBDEVICE3_LINK_BASE + 0xc17c) + +// Global PHY Registers +#define rGUSB2PHYCFG (USBDEVICE3_LINK_BASE + 0xc200) +#define rGUSB2I2CCTL (USBDEVICE3_LINK_BASE + 0xc240) +#define rGUSB2PHYACC (USBDEVICE3_LINK_BASE + 0xc280) +#define rGUSB3PIPECTL (USBDEVICE3_LINK_BASE + 0xc2c0) + +// Global FIFO Size Registers (0 <= num <= 15 @510) +#define rGTXFIFOSIZ(num) ((USBDEVICE3_LINK_BASE + 0xc300) + 0x04*num) +#define rGRXFIFOSIZ0 (USBDEVICE3_LINK_BASE + 0xc380) + +// Global Event Buffer Registers (DWC_USB3_DEVICE_NUM_INT = 1 @C510, GHWPARAMS1[20:15]) +#define rGEVNTADR_LO0 (USBDEVICE3_LINK_BASE + 0xc400) +#define rGEVNTADR_HI0 (USBDEVICE3_LINK_BASE + 0xc404) +#define rGEVNTSIZ0 (USBDEVICE3_LINK_BASE + 0xc408) +#define rGEVNTCOUNT0 (USBDEVICE3_LINK_BASE + 0xc40c) + +//========================== +// Device Registers (Dxxxx) +//========================== +// Device Common Registers +#define rDCFG (USBDEVICE3_LINK_BASE + 0xc700) +#define rDCTL (USBDEVICE3_LINK_BASE + 0xc704) +#define rDEVTEN (USBDEVICE3_LINK_BASE + 0xc708) +#define rDSTS (USBDEVICE3_LINK_BASE + 0xc70c) +#define rDGCMDPAR (USBDEVICE3_LINK_BASE + 0xc710) +#define rDGCMD (USBDEVICE3_LINK_BASE + 0xc714) +#define rDALEPENA (USBDEVICE3_LINK_BASE + 0xc720) + +// Device Endpoint Registers (0 <= ep <= 15) +#define rDOEPCMDPAR2(ep) ((USBDEVICE3_LINK_BASE + 0xc800) + 0x20*ep) +#define rDOEPCMDPAR1(ep) ((USBDEVICE3_LINK_BASE + 0xc804) + 0x20*ep) +#define rDOEPCMDPAR0(ep) ((USBDEVICE3_LINK_BASE + 0xc808) + 0x20*ep) +#define rDOEPCMD(ep) ((USBDEVICE3_LINK_BASE + 0xc80c) + 0x20*ep) + +#define rDIEPCMDPAR2(ep) ((USBDEVICE3_LINK_BASE + 0xc810) + 0x20*ep) +#define rDIEPCMDPAR1(ep) ((USBDEVICE3_LINK_BASE + 0xc814) + 0x20*ep) +#define rDIEPCMDPAR0(ep) ((USBDEVICE3_LINK_BASE + 0xc818) + 0x20*ep) +#define rDIEPCMD(ep) ((USBDEVICE3_LINK_BASE + 0xc81c) + 0x20*ep) + +//========================== +// USB DEVICE PHY CONTROL REGISTERS +//========================== +#define EXYNOS_PHY_LINKSYSTEM (USBDEVICE3_PHYCTRL_BASE + 0x04) +#define EXYNOS_PHY_UTMI (USBDEVICE3_PHYCTRL_BASE + 0x08) +#define EXYNOS_PHY_PIPE (USBDEVICE3_PHYCTRL_BASE + 0x0C) +#define EXYNOS_PHY_CLKPWR (USBDEVICE3_PHYCTRL_BASE + 0x10) +#define EXYNOS_PHY_REG0 (USBDEVICE3_PHYCTRL_BASE + 0x14) +#define EXYNOS_PHY_REG1 (USBDEVICE3_PHYCTRL_BASE + 0x18) +#define EXYNOS_PHY_PARAM0 (USBDEVICE3_PHYCTRL_BASE + 0x1C) +#define EXYNOS_PHY_PARAM1 (USBDEVICE3_PHYCTRL_BASE + 0x20) +#define EXYNOS_PHY_TERM (USBDEVICE3_PHYCTRL_BASE + 0x24) +#define EXYNOS_PHY_TEST (USBDEVICE3_PHYCTRL_BASE + 0x28) +#define EXYNOS_PHY_ADP (USBDEVICE3_PHYCTRL_BASE + 0x2C) +#define EXYNOS_PHY_BATCHG (USBDEVICE3_PHYCTRL_BASE + 0x30) +#define EXYNOS_PHY_RESUME (USBDEVICE3_PHYCTRL_BASE + 0x34) +#define EXYNOS_PHY_LINK_PORT (USBDEVICE3_PHYCTRL_BASE + 0x44) + +/* USBD 2.0 SFR */ +#define USBOTG_LINK_BASE (0x12140000) +#define USBOTG_PHY_BASE (0x12130000) + +#endif /* _EXYNOS5250_CPU_H */ diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Protocol/ExynosGpio.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Protocol/ExynosGpio.h new file mode 100644 index 000000000..35fe93bf6 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Protocol/ExynosGpio.h @@ -0,0 +1,199 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EXYNOS_GPIO_H__ +#define __EXYNOS_GPIO_H__ + +// +// Protocol interface structure +// +typedef struct _EXYNOS_GPIO EXYNOS_GPIO; + +// +// Data Types +// +typedef UINTN EXYNOS_GPIO_PIN; + +#define GPIO(Port, Pin) ((EXYNOS_GPIO_PIN)(((Port) << (16)) | (Pin))) +#define GPIO_PIN(x) ((EXYNOS_GPIO_PIN)(x) & (0xFFFF)) +#define GPIO_PORT(x) ((EXYNOS_GPIO_PIN)(x) >> (16)) + +typedef enum { + GPIO_MODE_INPUT = 0x00, + GPIO_MODE_OUTPUT_0 = 0x0E, + GPIO_MODE_OUTPUT_1 = 0x0F, + GPIO_MODE_SPECIAL_FUNCTION_2 = 0x02, + GPIO_MODE_SPECIAL_FUNCTION_3 = 0x03, + GPIO_MODE_SPECIAL_FUNCTION_4 = 0x04, + GPIO_MODE_SPECIAL_FUNCTION_5 = 0x05, + GPIO_MODE_SPECIAL_FUNCTION_6 = 0x06, + GPIO_MODE_SPECIAL_FUNCTION_7 = 0x07 +} EXYNOS_GPIO_MODE; + +typedef enum { + GPIO_PULL_NONE, + GPIO_PULL_UP, + GPIO_PULL_DOWN +} EXYNOS_GPIO_PULL; + +typedef enum { + GPIO_DRV_1X, + GPIO_DRV_2X, + GPIO_DRV_3X, + GPIO_DRV_4X +} EXYNOS_GPIO_STRN; + +// +// Function Prototypes +// +typedef +EFI_STATUS +(EFIAPI *EXYNOS_GPIO_GET) ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + OUT UINTN *Value + ); +/*++ + +Routine Description: + + Gets the state of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin to read + Value - state of the pin + +Returns: + + EFI_SUCCESS - GPIO state returned in Value + +--*/ + + +typedef +EFI_STATUS +(EFIAPI *EXYNOS_GPIO_SET) ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + IN EXYNOS_GPIO_MODE Mode + ); +/*++ + +Routine Description: + + Sets the state of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin to modify + Mode - mode to set + +Returns: + + EFI_SUCCESS - GPIO set as requested + +--*/ + + +typedef +EFI_STATUS +(EFIAPI *EXYNOS_GPIO_GET_MODE) ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + OUT EXYNOS_GPIO_MODE *Mode + ); +/*++ + +Routine Description: + + Gets the mode (function) of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin + Mode - pointer to output mode value + +Returns: + + EFI_SUCCESS - mode value retrieved + +--*/ + + +typedef +EFI_STATUS +(EFIAPI *EXYNOS_GPIO_SET_PULL) ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + IN EXYNOS_GPIO_PULL Direction + ); +/*++ + +Routine Description: + + Sets the pull-up / pull-down resistor of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin + Direction - pull-up, pull-down, or none + +Returns: + + EFI_SUCCESS - pin was set + +--*/ + +typedef EFI_STATUS +(EFIAPI *EXYNOS_GPIO_DRV) ( + IN EXYNOS_GPIO *This, + IN EXYNOS_GPIO_PIN Gpio, + IN EXYNOS_GPIO_STRN Strength + ); +/*++ + +Routine Description: + + Sets the Driving strength resistor of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin + Strength - 0=1x,1=2x,2=3x,3=4x + +Returns: + + EFI_SUCCESS - pin was set + +--*/ + + + +struct _EXYNOS_GPIO { + EXYNOS_GPIO_GET Get; + EXYNOS_GPIO_SET Set; + EXYNOS_GPIO_GET_MODE GetMode; + EXYNOS_GPIO_SET_PULL SetPull; + EXYNOS_GPIO_DRV SetStrength; +}; + +extern EFI_GUID gSamsungPlatformGpioProtocolGuid; + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Protocol/ExynosRng.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Protocol/ExynosRng.h new file mode 100644 index 000000000..58376b530 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Include/Protocol/ExynosRng.h @@ -0,0 +1,52 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EXYNOS_RNG_H__ +#define __EXYNOS_RNG_H__ + +// +// Protocol interface structure +// +typedef struct _EFI_RNG_PROTOCOL EFI_RNG_PROTOCOL; + +/** + * Generates a pseudorandom byte stream of the specified size. + * + * If Output is NULL, then return FALSE. + * + * @param[out] Output Pointer to buffer to receive random value + * @param[in] Size Size of random bytes to generate + * + * @retval TRUE Pseudorandom byte stream generated successfully. + * @retval FALSE Pseudorandom number generator fails to generate due to lack of entropy. + * + **/ +typedef +EFI_STATUS +(EFIAPI *EFI_RANDOM_BYTES) ( + IN CONST EFI_RNG_PROTOCOL *This, + OUT UINT8 *Output, + IN UINTN Size + ); + +/// +/// This protocol allows creating peudorandom random number using HW RNG engine. +/// +struct _EFI_RNG_PROTOCOL { + EFI_RANDOM_BYTES RandomBytes; +}; + +extern EFI_GUID gSamsungPlatformRngProtocolGuid; + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ExynosLib/ExynosLib.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ExynosLib/ExynosLib.c new file mode 100644 index 000000000..3dbee6de5 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ExynosLib/ExynosLib.c @@ -0,0 +1,51 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Base.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Platform/ArmPlatform.h> + +UINT32 +GpioBase ( + IN UINTN Port + ) +{ + + ASSERT( ((Port >= GPA0) && (Port <= GPY6)) + || ((Port >= GPX0) && (Port <= GPX3)) + || ((Port >= GPE0) && (Port <= GPH1)) + || ((Port >= GPV0) && (Port <= GPV4)) + || (Port == GPZ)); + + /*decide which part of gpio is being requested. give the corresponding base address*/ + if(Port >= 0x90) { + /* 0x0386_0000 */ + Port -= 0x90; + return (PcdGet32(PcdGpioPart4Base) + (Port*DISTANCE_BTWN_PORTS)); + }else if(Port >= 0x80) { + /* 0x10D1_0000 */ + Port -= 0x80; + return (PcdGet32(PcdGpioPart3Base) + (Port*DISTANCE_BTWN_PORTS)); + }else if(Port >= 0x70) { + /* 0x1340_0000 */ + Port -= 0x70; + return (PcdGet32(PcdGpioPart2Base) + (Port*DISTANCE_BTWN_PORTS)); + }else { + /* 0x1140_0000 */ + return (PcdGet32(PcdGpioPart1Base) + (Port*DISTANCE_BTWN_PORTS)); + } + + ASSERT(FALSE); return 0; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ExynosLib/ExynosLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ExynosLib/ExynosLib.inf new file mode 100644 index 000000000..f2b5f1dc2 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ExynosLib/ExynosLib.inf @@ -0,0 +1,42 @@ +#/** @file +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ExynosLib + FILE_GUID = d035f5c2-1b92-4746-9f6c-5ff6202970df + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = ExynosLib + +[Sources.common] + ExynosLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + +[LibraryClasses] + DebugLib + IoLib + +[Protocols] + +[Guids] + +[Pcd] + gExynosPkgTokenSpaceGuid.PcdGpioPart1Base + gExynosPkgTokenSpaceGuid.PcdGpioPart2Base + gExynosPkgTokenSpaceGuid.PcdGpioPart3Base + gExynosPkgTokenSpaceGuid.PcdGpioPart4Base diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/GdbSerialLib/GdbSerialLib.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/GdbSerialLib/GdbSerialLib.c new file mode 100644 index 000000000..db4eddf6e --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/GdbSerialLib/GdbSerialLib.c @@ -0,0 +1,118 @@ +/** @file + Basic serial IO abstaction for GDB + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Uefi.h> +#include <Library/GdbSerialLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Platform/ArmPlatform.h> + +RETURN_STATUS +EFIAPI +GdbSerialLibConstructor ( + VOID + ) +{ + return GdbSerialInit (115200, 0, 8, 1); +} + +RETURN_STATUS +EFIAPI +GdbSerialInit ( + IN UINT64 BaudRate, + IN UINT8 Parity, + IN UINT8 DataBits, + IN UINT8 StopBits + ) +{ + if ((Parity != 0) || (DataBits != 8) || (StopBits != 1)) { + return RETURN_UNSUPPORTED; + } + + if (BaudRate != 115200) { + // Could add support for different Baud rates.... + return RETURN_UNSUPPORTED; + } + + UINT32 Base = PcdGet32 (PcdGdbUartBase); + + // initialize baud rate generator to 115200 based on EB clock REFCLK24MHZ + MmioWrite32 (Base + UARTIBRD, UART_115200_IDIV); + MmioWrite32 (Base + UARTFBRD, UART_115200_FDIV); + + // no parity, 1 stop, no fifo, 8 data bits + MmioWrite32 (Base + UARTLCR_H, 0x60); + + // clear any pending errors + MmioWrite32 (Base + UARTECR, 0); + + // enable tx, rx, and uart overall + MmioWrite32 (Base + UARTCR, 0x301); + + return RETURN_SUCCESS; +} + +BOOLEAN +EFIAPI +GdbIsCharAvailable ( + VOID + ) +{ + UINT32 FR = PcdGet32 (PcdGdbUartBase) + UTRSTAT_OFFSET; + + if ((MmioRead32 (FR) & UART_RX_EMPTY_FLAG_MASK) == 0) { + return TRUE; + } else { + return FALSE; + } +} + +CHAR8 +EFIAPI +GdbGetChar ( + VOID + ) +{ + UINT32 FR = PcdGet32 (PcdGdbUartBase) + UTRSTAT_OFFSET; + UINT32 DR = PcdGet32 (PcdGdbUartBase) + URXH_OFFSET; + + while ((MmioRead32 (FR) & UART_RX_EMPTY_FLAG_MASK) == 0); + return MmioRead8 (DR); +} + +VOID +EFIAPI +GdbPutChar ( + IN CHAR8 Char + ) +{ + UINT32 FR = PcdGet32 (PcdGdbUartBase) + UTRSTAT_OFFSET; + UINT32 DR = PcdGet32 (PcdGdbUartBase) + UTXH_OFFSET; + + while ((MmioRead32 (FR) & UART_TX_EMPTY_FLAG_MASK) != 0); + MmioWrite8 (DR, Char); + return; +} + +VOID +GdbPutString ( + IN CHAR8 *String + ) +{ + while (*String != '\0') { + GdbPutChar (*String); + String++; + } +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/GdbSerialLib/GdbSerialLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/GdbSerialLib/GdbSerialLib.inf new file mode 100644 index 000000000..c557407e1 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/GdbSerialLib/GdbSerialLib.inf @@ -0,0 +1,40 @@ +#/** @file +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GdbSerialLib + FILE_GUID = E8EA1309-2F14-428f-ABE3-7016CE4B4305 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = GdbSerialLib + + CONSTRUCTOR = GdbSerialLibConstructor + + +[Sources.common] + GdbSerialLib.c + + +[Packages] + MdePkg/MdePkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + + +[LibraryClasses] + DebugLib + IoLib + +[FixedPcd] + gExynosPkgTokenSpaceGuid.PcdGdbUartBase diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/RealTimeClockLib/RealTimeClockLib.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/RealTimeClockLib/RealTimeClockLib.c new file mode 100644 index 000000000..2325a31b0 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/RealTimeClockLib/RealTimeClockLib.c @@ -0,0 +1,363 @@ +/** @file + Implement EFI RealTimeClock runtime services via RTC Lib. + + Currently this driver does not support runtime virtual calling. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/RealTimeClockLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Protocol/RealTimeClock.h> +#include <Guid/GlobalVariable.h> + + +/* + * Kimoon added on 2011.12.08 + */ +#include <Library/PcdLib.h> +#include <Platform/ArmPlatform.h> + +#define RTC_YEAR_DATUM 2000 + +unsigned bcd2bin(unsigned char val) +{ + return (val & 0x0f) + (val >> 4) * 10; +} + +unsigned char bin2bcd(unsigned val) +{ + return ((val / 10) << 4) + val % 10; +} + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + /* + * Kimoon added on 2011.12.08 + */ + UINT32 RtcBaseAddr; + BOOLEAN Retried = FALSE; + + DEBUG((EFI_D_INFO, "++%a:%d\n", __func__, __LINE__)); + + /* + * Check set time + */ + if (Time == NULL) + goto cleanUp; + + /* + * 1. Get RTC base address + */ + RtcBaseAddr = PcdGet32(PcdRtcBase); + + /* + * 2. Read registers + */ +RetryGetTime: + Time->Minute = MmioRead32(RtcBaseAddr + EXYNOS_BCDMIN); + Time->Hour = MmioRead32(RtcBaseAddr + EXYNOS_BCDHOUR); + Time->Day = MmioRead32(RtcBaseAddr + EXYNOS_BCDDAY); + Time->Month = MmioRead32(RtcBaseAddr + EXYNOS_BCDMON); + Time->Year = MmioRead32(RtcBaseAddr + EXYNOS_BCDYEAR); + Time->Second = MmioRead32(RtcBaseAddr + EXYNOS_BCDSEC); + + /* + * 3. if second value is 0, try to read registers to escape errors. + */ + if (Time->Second == 0 && !Retried) { + Retried = TRUE; + goto RetryGetTime; + } + + /* + * 4. Change BCD values to real values. + */ + Time->Second = bcd2bin(Time->Second); + Time->Minute = bcd2bin(Time->Minute); + Time->Hour = bcd2bin(Time->Hour); + Time->Day = bcd2bin(Time->Day); + Time->Month = bcd2bin(Time->Month); + Time->Year = bcd2bin(Time->Year) + RTC_YEAR_DATUM; + + // Update the Capabilities info + if (Capabilities != NULL) { + // PL031 runs at frequency 1Hz + Capabilities->Resolution = 1; + // Accuracy in ppm multiplied by 1,000,000, e.g. for 50ppm set 50,000,000 + Capabilities->Accuracy = 1000000; + // FALSE: Setting the time does not clear the values below the resolution level + Capabilities->SetsToZero = FALSE; + } + + + DEBUG((EFI_D_INFO, "--%a:%d (%d/%d/%d %d:%d:%d)\n", + __func__, __LINE__, + Time->Year, Time->Month, Time->Day, Time->Hour, Time->Minute, Time->Second)); + return EFI_SUCCESS; + +cleanUp: + DEBUG((EFI_D_ERROR, "ERROR: %a:%d\n", __func__, __LINE__)); + return EFI_DEVICE_ERROR; + +} + + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ) +{ + /* + * Kimoon added on 2011.12.08 + */ + UINT32 RtcBaseAddr; + + DEBUG((EFI_D_ERROR, "++%a:%d (%d/%d/%d %d:%d:%d)\n", + __func__, __LINE__, + Time->Year, Time->Month, Time->Day, Time->Hour, Time->Minute, Time->Second)); + + /* + * Check set time + */ + if (Time == NULL) + goto cleanUp; + + /* + * The RTC will only support a BCD year value of 0 - 99. The year datum is + * 2000, so any dates greater than 2099 will fail unless the datum is + * adjusted. + */ + if ((Time->Year < RTC_YEAR_DATUM) || (Time->Year - RTC_YEAR_DATUM > 99)) { + DEBUG((EFI_D_ERROR, "RTC cannot support a year greater than %d or less than %d (value %d)\n", + (RTC_YEAR_DATUM + 99), RTC_YEAR_DATUM, Time->Year)); + goto cleanUp; + } + + /* + * 1. Get RTC base address + */ + RtcBaseAddr = PcdGet32(PcdRtcBase); + + /* + * 2. Set EXYNOS_RTCCON_RTCEN to Set BCD registers + * &= ~EXYNOS_RTCCON_RTCEN + * |= EXYNOS_RTCCON_RTCEN + */ + MmioAndThenOr32(RtcBaseAddr + EXYNOS_RTCCON, \ + ~EXYNOS_RTCCON_RTCEN, EXYNOS_RTCCON_RTCEN); + + /* + * 3. Set BCD registers + */ + MmioWrite32(RtcBaseAddr + EXYNOS_BCDSEC, bin2bcd(Time->Second)); + MmioWrite32(RtcBaseAddr + EXYNOS_BCDMIN, bin2bcd(Time->Minute)); + MmioWrite32(RtcBaseAddr + EXYNOS_BCDHOUR, bin2bcd(Time->Hour)); + MmioWrite32(RtcBaseAddr + EXYNOS_BCDDAY, bin2bcd(Time->Day)); + MmioWrite32(RtcBaseAddr + EXYNOS_BCDMON, bin2bcd(Time->Month)); + MmioWrite32(RtcBaseAddr + EXYNOS_BCDYEAR, bin2bcd(Time->Year - RTC_YEAR_DATUM)); + + /* + * 4. Clear EXYNOS_RTCCON_RTCEN to close setting BCD registers + * &= ~EXYNOS_RTCCON_RTCEN + */ + MmioAndThenOr32(RtcBaseAddr + EXYNOS_RTCCON, \ + ~EXYNOS_RTCCON_RTCEN, (0<<0)); + + DEBUG((EFI_D_ERROR, "--%a:%d\n", __func__, __LINE__)); + return EFI_SUCCESS; + +cleanUp: + DEBUG((EFI_D_ERROR, "ERROR: %a:%d\n", __func__, __LINE__)); + return EFI_DEVICE_ERROR; + +} + + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + // Not a required feature + return EFI_UNSUPPORTED; +} + + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + // Not a required feature + return EFI_UNSUPPORTED; +} + + + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +LibRtcInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HANDLE Handle; + EFI_TIME Time; + + /* + * Kimoon added on 2011.12.08 + */ + DEBUG((EFI_D_INFO, "++%a:%d\n", __func__, __LINE__)); + + /* + * Mask RTC gating (bit clear) + */ + MmioAndThenOr32((PcdGet32(PcdCmuBase) + CLK_GATE_IP_PERIR), \ + ~CLK_RTC_OFFSET, CLK_RTC_MASK); + + /* + * Unmask RTC gating (bit set) + */ + MmioAndThenOr32((PcdGet32(PcdCmuBase) + CLK_GATE_IP_PERIR), \ + ~CLK_RTC_OFFSET, CLK_RTC_UNMASK); + + + // Setup the setters and getters + gRT->GetTime = LibGetTime; + gRT->SetTime = LibSetTime; + gRT->GetWakeupTime = LibGetWakeupTime; + gRT->SetWakeupTime = LibSetWakeupTime; + + Time.Second = 0; + Time.Minute = 0; + Time.Hour = 9; + Time.Day = 15; + Time.Month = 3; + Time.Year = 2012; + + LibSetTime(&Time); + + // Install the protocol + Handle = NULL; + gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiRealTimeClockArchProtocolGuid, NULL, + NULL + ); + + DEBUG((EFI_D_INFO, "--%a:%d\n", __func__, __LINE__)); + return EFI_SUCCESS; +} + + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Only needed if you are going to support the OS calling RTC functions in virtual mode. + // You will need to call EfiConvertPointer (). To convert any stored physical addresses + // to virtual address. After the OS transistions to calling in virtual mode, all future + // runtime calls will be made in virtual mode. + // + return; +} + + + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/RealTimeClockLib/RealTimeClockLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/RealTimeClockLib/RealTimeClockLib.inf new file mode 100644 index 000000000..78c6937a6 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/RealTimeClockLib/RealTimeClockLib.inf @@ -0,0 +1,42 @@ +#/** @file +# Memory Status Code Library for UEFI drivers +# +# Lib to provide memory journal status code reporting Routines +# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR> +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateRealTimeClockLib + FILE_GUID = B661E02D-A90B-42AB-A5F9-CF841AAA43D9 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RealTimeClockLib + + +[Sources.common] + RealTimeClockLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + +[LibraryClasses] + IoLib + UefiLib + DebugLib + +[Pcd.common] + gExynosPkgTokenSpaceGuid.PcdRtcBase + gExynosPkgTokenSpaceGuid.PcdCmuBase diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ResetSystemLib/ResetSystemLib.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ResetSystemLib/ResetSystemLib.c new file mode 100644 index 000000000..295a42546 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ResetSystemLib/ResetSystemLib.c @@ -0,0 +1,241 @@ +/** @file + Template library implementation to support ResetSystem Runtime call. + + Fill in the templates with what ever makes you system reset. + + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include <PiDxe.h> + +#include <Library/UefiRuntimeLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/ArmLib.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/EfiResetSystemLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/CacheMaintenanceLib.h> +#include <Platform/ArmPlatform.h> + +#include <Guid/EventGroup.h> + + +/* Round off to 4KB pages */ +#define ROUND_TO_PAGE(x) (x & 0xfffff000) + + +UINT32 gPmuBaseAddress = 0; +EFI_EVENT VirtualAddressChangeEvent = NULL; + +VOID DestroyExynosMemMap(VOID); +typedef VOID (EFIAPI *ptrImageStart)(VOID); + +/** + Virtual address change notification call back. It converts global pointer + to virtual address. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context, which is + always zero in current implementation. +**/ +VOID +EFIAPI +VirtualAddressChangeCallBack ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRT->ConvertPointer(0, (VOID**)&gPmuBaseAddress); + gRT->ConvertPointer(0, (VOID**)&gRT); +} + + +VOID +DestroyExynosMemMap ( + VOID + ) +{ + EFI_STATUS Status; + UINTN MemoryMapSize; + EFI_MEMORY_DESCRIPTOR *MemoryMap; + UINTN MapKey; + UINTN DescriptorSize; + UINTN DescriptorVersion; + UINTN Pages; + + MemoryMap = NULL; + MemoryMapSize = 0; + do { + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + + Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1; + MemoryMap = AllocatePages (Pages); + + // + // Get System MemoryMap + // + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + // Don't do anything between the GetMemoryMap() and ExitBootServices() + if (!EFI_ERROR (Status)) { + Status = gBS->ExitBootServices (gImageHandle, MapKey); + if (EFI_ERROR (Status)) { + FreePages (MemoryMap, Pages); + MemoryMap = NULL; + MemoryMapSize = 0; + } + } + } + } while (EFI_ERROR (Status)); + + //Clean and invalidate caches. + WriteBackInvalidateDataCache(); + InvalidateInstructionCache(); + + //Turning off Caches and MMU + ArmDisableDataCache (); + ArmDisableInstructionCache (); + ArmDisableMmu (); +} + + + +/** + Resets the entire platform. + + @param ResetType The type of reset to perform. + @param ResetStatus The status code for the reset. + @param DataSize The size, in bytes, of WatchdogData. + @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + Unicode string, optionally followed by additional binary data. + +**/ +EFI_STATUS +EFIAPI +LibResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) +{ + volatile UINT32 count = 0; + + if (EfiAtRuntime()) + { + while (count < 0x1000000) + { + count++; + } + } + + switch (ResetType) { + case EfiResetShutdown: + case EfiResetCold: + case EfiResetWarm: + //Perform warm reset of the system by jumping to the begining of the FV + //((ptrImageStart)PcdGet32(PcdFvBaseAddress))(); + //break; + default: + if(EfiAtRuntime () == 0) + { + DestroyExynosMemMap(); + } + + /* Perform cold reset of the system - should not return */ + MmioWrite32 ((gPmuBaseAddress + SWRESET_OFFSET), 0x01); + while ((MmioRead32(gPmuBaseAddress + SWRESET_OFFSET)) != 0x1); + break; + } + + // If the reset didn't work, return an error. + ASSERT (FALSE); + return EFI_SUCCESS; +} + + + +/** + Initialize any infrastructure required for LibResetSystem () to function. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +LibInitializeResetSystem ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + EFI_GCD_MEMORY_SPACE_DESCRIPTOR PmuMemoryDescriptor; + + gPmuBaseAddress = PcdGet32(PcdPmuBase); + + /* + * Get the GCD Memory Descriptor specified by WdtBaseAddress page boundary + */ + Status = gDS->GetMemorySpaceDescriptor (ROUND_TO_PAGE(gPmuBaseAddress), + &PmuMemoryDescriptor); + ASSERT_EFI_ERROR (Status); + + /* + * Mark the 4KB region as EFI_RUNTIME_MEMORY so the OS + * will allocate a virtual address range. + */ + Status = gDS->SetMemorySpaceAttributes ( + ROUND_TO_PAGE(gPmuBaseAddress), + EFI_PAGE_SIZE, + PmuMemoryDescriptor.Attributes | EFI_MEMORY_RUNTIME); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + VirtualAddressChangeCallBack, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &VirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + + + + + return EFI_SUCCESS; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ResetSystemLib/ResetSystemLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ResetSystemLib/ResetSystemLib.inf new file mode 100644 index 000000000..314078c32 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/ResetSystemLib/ResetSystemLib.inf @@ -0,0 +1,52 @@ +#/** @file +# Reset System lib to make it easy to port new platforms +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ResetSystemLib + FILE_GUID = CEFFA65C-B568-453e-9E11-B81AE683D035 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = EfiResetSystemLib + + +[Sources.common] + ResetSystemLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + +[LibraryClasses] + DxeServicesTableLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiRuntimeLib + DebugLib + BaseLib + IoLib + MemoryAllocationLib + ArmLib + CacheMaintenanceLib + +[Pcd] + gArmTokenSpaceGuid.PcdFvBaseAddress + gExynosPkgTokenSpaceGuid.PcdPmuBase + +[Guids] + gEfiEventVirtualAddressChangeGuid diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/SerialPortLib/SerialPortLib_Evt1.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/SerialPortLib/SerialPortLib_Evt1.c new file mode 100755 index 000000000..1e5791bd8 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/SerialPortLib/SerialPortLib_Evt1.c @@ -0,0 +1,159 @@ +/** @file + Serial I/O Port library functions with no library constructor/destructor + + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Include/Uefi.h> +#include <Library/SerialPortLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Platform/ArmPlatform.h> +#include <Library/DebugLib.h> + +/* + + Programmed hardware of Serial port. + Irrespective of the previous settings Initialize it to current requirement +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( + VOID + ) +{ + UINT32 UARTConsoleBase; + UINT32 Tmp; + + UARTConsoleBase=PcdGet32(PcdConsoleUartBase); + + // GPIO + MmioWrite32(0x11400000, 0x00002222); + MmioWrite32(0x11400020, 0x222222); + MmioWrite32(0x11400160, 0x2222); + + // CMU + Tmp = MmioRead32(0x10020250); +// DEBUG ((EFI_D_ERROR, "%X \n", Tmp)); + + Tmp &= ~((0xF << 16) + (0xF << 12) + (0xF << 8) + (0xF << 4) + (0xF << 0)); + Tmp |= ((0x6 << 16) + (0x6 << 12) + (0x6 << 8) + (0x6 << 4) + (0x6 << 0)); + MmioWrite32 (0x10020250, Tmp); + + Tmp = MmioRead32(0x10020558); + Tmp &= ~((0xF << 16) + (0xF << 12) + (0xF << 8) + (0xF << 4) + (0xF << 0)); + Tmp |= ((0x7 << 16) + (0x7 << 12) + (0x7 << 8) + (0x7 << 4) + (0x7 << 0)); + MmioWrite32 (0x10020558, Tmp); + + // UART + MmioWrite32(UARTConsoleBase, 0x3); + MmioWrite32(UARTConsoleBase+0x4, 0x3C5); + MmioWrite32(UARTConsoleBase+0x8, 0x111); + MmioWrite32(UARTConsoleBase+0x28, 0x23); + MmioWrite32(UARTConsoleBase+0x2C, 0x2); +/* + MmioWrite32(UARTConsoleBase+0x20, 0x4F); + MmioWrite32(UARTConsoleBase+0x20, 0x4F); + MmioWrite32(UARTConsoleBase+0x20, 0x4F); + MmioWrite32(UARTConsoleBase+0x20, 0x4F); + MmioWrite32(UARTConsoleBase+0x20, 0x4F); + MmioWrite32(UARTConsoleBase+0x20, 0x4F); +*/ + // For WindDebug Uart initialization + UARTConsoleBase=PcdGet32(PcdWinDebugUartBase); + MmioWrite32(UARTConsoleBase, 0x3); + MmioWrite32(UARTConsoleBase+0x4, 0x3C5); + MmioWrite32(UARTConsoleBase+0x8, 0x111); + MmioWrite32(UARTConsoleBase+0x28, 0x35); + MmioWrite32(UARTConsoleBase+0x2C, 0x4); + + return EFI_SUCCESS; +} + +/** + Write data to serial device. + + @param Buffer Point of data buffer which need to be writed. + @param NumberOfBytes Number of output bytes which are cached in Buffer. + + @retval 0 Write data failed. + @retval !0 Actual number of bytes writed to serial device. + +**/ +UINTN +EFIAPI +SerialPortWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINTN Count; + UINT32 UARTConsoleBase; + + UARTConsoleBase=PcdGet32(PcdConsoleUartBase); + for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) { + while ((MmioRead32 (UARTConsoleBase + UTRSTAT_OFFSET) & UART_TX_EMPTY_FLAG_MASK) == 0); + MmioWrite8 (UARTConsoleBase + UTXH_OFFSET, *Buffer); + } + + return NumberOfBytes; +} + +/** + Read data from serial device and save the datas in buffer. + + @param Buffer Point of data buffer which need to be writed. + @param NumberOfBytes Number of output bytes which are cached in Buffer. + + @retval 0 Read data failed. + @retval !0 Aactual number of bytes read from serial device. + +**/ +UINTN +EFIAPI +SerialPortRead ( + OUT UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINTN Count; + UINT32 UARTConsoleBase; + + UARTConsoleBase=PcdGet32(PcdConsoleUartBase); + for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) { + while ((MmioRead32 (UARTConsoleBase + UTRSTAT_OFFSET) & UART_RX_EMPTY_FLAG_MASK) == 0); + *Buffer = MmioRead8 (UARTConsoleBase + URXH_OFFSET); + } + + return NumberOfBytes; +} + +/** + Check to see if any data is avaiable to be read from the debug device. + + @retval EFI_SUCCESS At least one byte of data is avaiable to be read + @retval EFI_NOT_READY No data is avaiable to be read + @retval EFI_DEVICE_ERROR The serial device is not functioning properly + +**/ +BOOLEAN +EFIAPI +SerialPortPoll ( + VOID + ) +{ + UINT32 UARTConsoleBase; + UARTConsoleBase=PcdGet32(PcdConsoleUartBase); + + return ((MmioRead32 (UARTConsoleBase + UTRSTAT_OFFSET) & UART_RX_EMPTY_FLAG_MASK) != 0); +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/SerialPortLib/SerialPortLib_Evt1.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/SerialPortLib/SerialPortLib_Evt1.inf new file mode 100755 index 000000000..de89bad23 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/SerialPortLib/SerialPortLib_Evt1.inf @@ -0,0 +1,38 @@ +#/** @file +# +# Component discription file for NorFlashDxe module +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SerialPortLib + FILE_GUID = 8ecefc8f-a2c4-4091-b80f-20f7aeb0567f + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = SerialPortLib + +[Sources.common] + SerialPortLib_Evt1.c + +[LibraryClasses] + IoLib + +[Packages] + MdePkg/MdePkg.dec + # ArmPlatformPkg/ArmPlatformPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + +[FixedPcd] + gExynosPkgTokenSpaceGuid.PcdConsoleUartBase + gExynosPkgTokenSpaceGuid.PcdWinDebugUartBase + gExynosPkgTokenSpaceGuid.PcdCmuBase diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/TimerLib/TimerLib.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/TimerLib/TimerLib.c new file mode 100644 index 000000000..f828b53fa --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/TimerLib/TimerLib.c @@ -0,0 +1,287 @@ +/** @file + + Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Base.h> + +#include <Library/BaseLib.h> +#include <Library/TimerLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Platform/ArmPlatform.h> +#include <Library/ExynosTimerLib.h> + + +// Setup SP810's Timer2 for managing delay functions. And Timer3 for Performance counter +// Note: ArmVE's Timer0 and Timer1 are used by TimerDxe. +RETURN_STATUS +EFIAPI +TimerConstructor ( + VOID + ) +{ + UINT32 PWMTimerBase; + UINT32 Tmp; + + PWMTimerBase = PcdGet32(PcdPWMTimerBase); + +/** + This function is for initializing for PWM Timer + Timer 2 = > Delay Counter + Timer 3 = > Performance Counter +**/ +// PWM Input Clock(ACLK_100) is 100 Mhz so We need to prescale about 1Mhz to make udelay function + Tmp = MmioRead32 (PWMTimerBase + PWM_TCFG0_OFFSET); + Tmp &= ~(0xFF << 8); + Tmp |= (0x63 << 8); + MmioWrite32 ((PWMTimerBase + PWM_TCFG0_OFFSET), Tmp); + MmioWrite32 ((PWMTimerBase + PWM_TCFG1_OFFSET), 0x0); + +// PWM Timer INT disable + Tmp = MmioRead32 (PWMTimerBase + PWM_TINT_CSTAT_OFFSET); + Tmp &= ~(0x3 << 2); + MmioWrite32 ((PWMTimerBase + PWM_TINT_CSTAT_OFFSET), Tmp); + +// PWM Timer 2,3 make to stop + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + Tmp &= ~(0xFF << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + +// PWM Timer 3 used by Free running counter with Auto re-load mode + MmioWrite32 ((PWMTimerBase + PWM_TCNTB3_OFFSET), 0xFFFFFFFF); +// Set and Clear PWM Manually update for Timer 3 + Tmp |= (0x2 << 16); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + Tmp &= ~(0x2 << 16); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); +// Set Auto re-load and start Timer + Tmp |= (0x9 << 16); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + DEBUG ((EFI_D_ERROR, "Timer 2,3 Enabled\n")); + + return RETURN_SUCCESS; +} + +/** + Stalls the CPU for at least the given number of microseconds. + + Stalls the CPU for the number of microseconds specified by MicroSeconds. + + @param MicroSeconds The minimum number of microseconds to delay. + + @return The value of MicroSeconds inputted. + +**/ +UINTN +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + UINT32 Tmp; + UINT32 PWMTimerBase; + UINT32 i = 0; + + PWMTimerBase=PcdGet32(PcdPWMTimerBase); + /* load the timer count register */ + MmioWrite32 ((PWMTimerBase + PWM_TCNTB2_OFFSET), MicroSeconds); + + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + + /* Stop Timer 2 */ + Tmp &= ~(0xF << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + /* Set and Clear for Manually Update Counter Buffer */ + Tmp |= (0x2 << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + Tmp &= ~(0x2 << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + /* Start Timer 2 */ + Tmp |= (0x1 << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + /* + * When ARM clock is 1GHz, 1 clock time is 1us. + * Simply counting, CounterValue maybe can't be updated within 10 instruction execution. + * So it is needed to check CounterValue register a couple of times + */ + do { + /* Doesn't need to check if timer starts */ + if ((MmioRead32 (PWMTimerBase + PWM_TCNTO2_OFFSET)) != 0) + break; + /* Supports meaningful delay */ + if (MicroSeconds < 10000) + break; + /* Timer should start Within this time */ + if (i++ > 20) + break; + } while ((MmioRead32 (PWMTimerBase + PWM_TCNTO2_OFFSET)) == 0); + + /* Wait for requested delay time */ + while (MmioRead32 (PWMTimerBase + PWM_TCNTO2_OFFSET) > 0) { + ; + } + + /* Stop Timer 2 */ + Tmp &= ~(0xF << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + return MicroSeconds; +} + +/** + Stalls the CPU for at least the given number of nanoseconds. + + Stalls the CPU for the number of nanoseconds specified by NanoSeconds. + + @param NanoSeconds The minimum number of nanoseconds to delay. + + @return The value of NanoSeconds inputted. + +**/ +UINTN +EFIAPI +NanoSecondDelay ( + IN UINTN NanoSeconds + ) +{ + UINT32 MicroSeconds; + UINT32 Tmp; + UINT32 PWMTimerBase; + + PWMTimerBase=PcdGet32(PcdPWMTimerBase); + + // Round up to 1us Tick Number + MicroSeconds = (UINT32)NanoSeconds / 1000; + MicroSeconds += ((UINT32)NanoSeconds % 1000) == 0 ? 0 : 1; + // load the timer count register + MmioWrite32 ((PWMTimerBase + PWM_TCNTB2_OFFSET), MicroSeconds); + + Tmp = MmioRead32 (PWMTimerBase + PWM_TCON_OFFSET); + //Stop Timer 2 + Tmp &= ~(0xF << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + //Set and Clear for Manually Update Counter Buffer + Tmp |= (0x2 << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + Tmp &= ~(0x2 << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + //Start Timer 2 + Tmp |= (0x1 << 12); + MmioWrite32 ((PWMTimerBase + PWM_TCON_OFFSET), Tmp); + + //Wait for requested delay time + while (MmioRead32 (PWMTimerBase + PWM_TCNTO2_OFFSET) > 0) { + ; + } + + return NanoSeconds; +} + +/** + Retrieves the current value of a 64-bit free running performance counter. + + The counter can either count up by 1 or count down by 1. If the physical + performance counter counts by a larger increment, then the counter values + must be translated. The properties of the counter can be retrieved from + GetPerformanceCounterProperties(). + + @return The current value of the free running performance counter. + +**/ +UINT64 +EFIAPI +GetPerformanceCounter ( + VOID + ) +{ + UINT32 PWMTimerBase; + + PWMTimerBase=PcdGet32(PcdPWMTimerBase); + // Free running 64-bit/32-bit counter is needed here. + // Don't think we need this to boot, just to do performance profile + // ASSERT (FALSE); + UINT32 val = MmioRead32 (PWMTimerBase + PWM_TCNTO3_OFFSET); + + ASSERT(val > 0); + + return (UINT64)val; +} + + +/** + Retrieves the 64-bit frequency in Hz and the range of performance counter + values. + + If StartValue is not NULL, then the value that the performance counter starts + with immediately after is it rolls over is returned in StartValue. If + EndValue is not NULL, then the value that the performance counter end with + immediately before it rolls over is returned in EndValue. The 64-bit + frequency of the performance counter in Hz is always returned. If StartValue + is less than EndValue, then the performance counter counts up. If StartValue + is greater than EndValue, then the performance counter counts down. For + example, a 64-bit free running counter that counts up would have a StartValue + of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter + that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0. + + @param StartValue The value the performance counter starts with when it + rolls over. + @param EndValue The value that the performance counter ends with before + it rolls over. + + @return The frequency in Hz. + +**/ +UINT64 +EFIAPI +GetPerformanceCounterProperties ( + OUT UINT64 *StartValue, OPTIONAL + OUT UINT64 *EndValue OPTIONAL + ) +{ + if (StartValue != NULL) { + // Timer starts with the reload value + *StartValue = (UINT64)0ULL; + } + + if (EndValue != NULL) { + // Timer counts up to 0xFFFFFFFF + *EndValue = 0xFFFFFFFF; + } + + return 1000000; +} + +/** + Converts elapsed ticks of performance counter to time in nanoseconds. + + This function converts the elapsed ticks of running performance counter to + time value in unit of nanoseconds. + + @param Ticks The number of elapsed ticks of running performance counter. + + @return The elapsed time in nanoseconds. + +**/ +UINT64 +EFIAPI +GetTimeInNanoSecond ( + IN UINT64 Ticks +) +{ + ASSERT (TRUE); + return 0; +} + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/TimerLib/TimerLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/TimerLib/TimerLib.inf new file mode 100644 index 000000000..b8b745aa3 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Library/TimerLib/TimerLib.inf @@ -0,0 +1,41 @@ +#/** @file +# Timer library implementation +# +# +# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Exynos4210TimerLib + FILE_GUID = 34cfa85e-a798-4e46-8d38-1843d7a0caea + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib + + CONSTRUCTOR = TimerConstructor + +[Sources.common] + TimerLib.c + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + +[LibraryClasses] + DebugLib + IoLib + BaseLib + +[Pcd.common] + gExynosPkgTokenSpaceGuid.PcdPWMTimerBase diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeiLib.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeiLib.c new file mode 100644 index 000000000..affc7da58 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeiLib.c @@ -0,0 +1,182 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include <PiPei.h> + +#include <Library/ArmPlatformLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> + +VOID +BuildMemoryTypeInformationHob ( + VOID + ); + +VOID +InitMmu ( + VOID + ) +{ + ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable; + VOID *TranslationTableBase; + UINTN TranslationTableSize; + + // Get Virtual Memory Map from the Platform Library + ArmPlatformGetVirtualMemoryMap(&MemoryTable); + + //Note: Because we called PeiServicesInstallPeiMemory() before to call InitMmu() the MMU Page Table resides in + // DRAM (even at the top of DRAM as it is the first permanent memory allocation) + ArmConfigureMmu (MemoryTable, &TranslationTableBase, &TranslationTableSize); +} + +/*++ + +Routine Description: + + + +Arguments: + + FileHandle - Handle of the file being invoked. + PeiServices - Describes the list of possible PEI Services. + +Returns: + + Status - EFI_SUCCESS if the boot mode could be set + +--*/ +EFI_STATUS +EFIAPI +MemoryPeim ( + IN EFI_PHYSICAL_ADDRESS UefiMemoryBase, + IN UINT64 UefiMemorySize + ) +{ + EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttributes; + UINT64 ResourceLength; + EFI_PEI_HOB_POINTERS NextHob; + EFI_PHYSICAL_ADDRESS FdTop; + EFI_PHYSICAL_ADDRESS SystemMemoryTop; + EFI_PHYSICAL_ADDRESS ResourceTop; + BOOLEAN Found; + + // Ensure PcdSystemMemorySize has been set + ASSERT (PcdGet32 (PcdSystemMemorySize) != 0); + + // + // Now, the permanent memory has been installed, we can call AllocatePages() + // + ResourceAttributes = ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_TESTED + ); + + // Reserved the memory space occupied by the firmware volume + BuildResourceDescriptorHob ( + EFI_RESOURCE_MEMORY_MAPPED_IO, + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE, + 0x10000000,//PcdGet32 (PcdPmuBase), + 0x087FFFFF + ); + + // Reserved the memory space occupied by the firmware volume + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + ResourceAttributes, + PcdGet32 (PcdSystemMemoryBase), + PcdGet32 (PcdSystemMemorySize) + ); + + SystemMemoryTop = PcdGet32 (PcdSystemMemoryBase) + PcdGet32 (PcdSystemMemorySize); + FdTop = PcdGet32(PcdFdBaseAddress) + PcdGet32(PcdFdSize); + + // EDK2 does not have the concept of boot firmware copied into DRAM. To avoid the DXE + // core to overwrite this area we must mark the region with the attribute non-present + if ((PcdGet32 (PcdFdBaseAddress) >= PcdGet32 (PcdSystemMemoryBase)) && (FdTop <= SystemMemoryTop)) { + Found = FALSE; + + // Search for System Memory Hob that contains the firmware + NextHob.Raw = GetHobList (); + while ((NextHob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, NextHob.Raw)) != NULL) { + if ((NextHob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) && + (PcdGet32(PcdFdBaseAddress) >= NextHob.ResourceDescriptor->PhysicalStart) && + (FdTop <= NextHob.ResourceDescriptor->PhysicalStart + NextHob.ResourceDescriptor->ResourceLength)) + { + ResourceAttributes = NextHob.ResourceDescriptor->ResourceAttribute; + ResourceLength = NextHob.ResourceDescriptor->ResourceLength; + ResourceTop = NextHob.ResourceDescriptor->PhysicalStart + ResourceLength; + + if (PcdGet32(PcdFdBaseAddress) == NextHob.ResourceDescriptor->PhysicalStart) { + if (SystemMemoryTop == FdTop) { + NextHob.ResourceDescriptor->ResourceAttribute = ResourceAttributes & ~EFI_RESOURCE_ATTRIBUTE_PRESENT; + } else { + // Create the System Memory HOB for the firmware with the non-present attribute + BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY, + ResourceAttributes & ~EFI_RESOURCE_ATTRIBUTE_PRESENT, + PcdGet32(PcdFdBaseAddress), + PcdGet32(PcdFdSize)); + + DEBUG((EFI_D_ERROR, "PcdFdBaseAddress : 0x%X, PcdFdSize: 0x%X\n", PcdGet32(PcdFdBaseAddress),PcdGet32(PcdFdSize))); + + // Top of the FD is system memory available for UEFI + NextHob.ResourceDescriptor->PhysicalStart += PcdGet32(PcdFdSize); + NextHob.ResourceDescriptor->ResourceLength -= PcdGet32(PcdFdSize); + } + } else { + // Create the System Memory HOB for the firmware with the non-present attribute + BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY, + ResourceAttributes & ~EFI_RESOURCE_ATTRIBUTE_PRESENT, + PcdGet32(PcdFdBaseAddress), + PcdGet32(PcdFdSize)); + DEBUG((EFI_D_ERROR, "PcdFdBaseAddress : 0x%X, PcdFdSize: 0x%X\n", PcdGet32(PcdFdBaseAddress),PcdGet32(PcdFdSize))); + + // Update the HOB + NextHob.ResourceDescriptor->ResourceLength = PcdGet32(PcdFdBaseAddress) - NextHob.ResourceDescriptor->PhysicalStart; + + // If there is some memory available on the top of the FD then create a HOB + if (FdTop < NextHob.ResourceDescriptor->PhysicalStart + ResourceLength) { + // Create the System Memory HOB for the remaining region (top of the FD) + BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY, + ResourceAttributes, + FdTop, + ResourceTop - FdTop); + DEBUG((EFI_D_ERROR, "FdTop : 0x%X, ResourceTop - FdTop : 0x%X\n", FdTop, ResourceTop - FdTop)); + } + } + Found = TRUE; + break; + } + NextHob.Raw = GET_NEXT_HOB (NextHob); + } + + ASSERT(Found); + } + + // Build Memory Allocation Hob + InitMmu (); + + if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) { + // Optional feature that helps prevent EFI memory map fragmentation. + BuildMemoryTypeInformationHob (); + } + + return EFI_SUCCESS; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeiLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeiLib.inf new file mode 100644 index 000000000..3afbfc8d4 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeiLib.inf @@ -0,0 +1,69 @@ +#/** @file +# +# Copyright (c) 2011, ARM Ltd. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmMemoryInitPeiLib + FILE_GUID = 55ddb6e0-70b5-11e0-b33e-0002a5d5c51b + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformPeiLib + +[Sources] + MemoryInitPeiLib.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + +[LibraryClasses] + DebugLib + HobLib + ArmLib + ArmPlatformLib + +[Guids] + gEfiMemoryTypeInformationGuid + +[Ppis] + +[FeaturePcd] + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob + +[FixedPcd] + gArmTokenSpaceGuid.PcdFdBaseAddress + gArmTokenSpaceGuid.PcdFdSize + + gArmTokenSpaceGuid.PcdSystemMemoryBase + gArmTokenSpaceGuid.PcdSystemMemorySize + gArmPlatformTokenSpaceGuid.PcdSystemMemoryUefiRegionSize + + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData + + gExynosPkgTokenSpaceGuid.PcdPmuBase + +[depex] + TRUE diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeim.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeim.c new file mode 100644 index 000000000..0fc6b4aa9 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeim.c @@ -0,0 +1,157 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include <PiPei.h> + +// +// The protocols, PPI and GUID defintions for this module +// +#include <Ppi/MasterBootMode.h> +#include <Ppi/BootInRecoveryMode.h> +#include <Guid/MemoryTypeInformation.h> +// +// The Library classes this module consumes +// +#include <Library/ArmPlatformLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/PeimEntryPoint.h> +#include <Library/PeiServicesLib.h> +#include <Library/PcdLib.h> + +EFI_STATUS +EFIAPI +MemoryPeim ( + IN EFI_PHYSICAL_ADDRESS UefiMemoryBase, + IN UINT64 UefiMemorySize + ); + +// May want to put this into a library so you only need the PCD settings if you are using the feature? +VOID +BuildMemoryTypeInformationHob ( + VOID + ) +{ + EFI_MEMORY_TYPE_INFORMATION Info[10]; + + Info[0].Type = EfiACPIReclaimMemory; + Info[0].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory); + Info[1].Type = EfiACPIMemoryNVS; + Info[1].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS); + Info[2].Type = EfiReservedMemoryType; + Info[2].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiReservedMemoryType); + Info[3].Type = EfiRuntimeServicesData; + Info[3].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesData); + Info[4].Type = EfiRuntimeServicesCode; + Info[4].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesCode); + Info[5].Type = EfiBootServicesCode; + Info[5].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesCode); + Info[6].Type = EfiBootServicesData; + Info[6].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesData); + Info[7].Type = EfiLoaderCode; + Info[7].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderCode); + Info[8].Type = EfiLoaderData; + Info[8].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderData); + + DEBUG ((EFI_D_ERROR, "BuildMemoryTypeInformationHob PcdMemoryTypeEfiRuntimeServicesCode: %d, PcdMemoryTypeEfiRuntimeServicesData: %d\n", Info[4].NumberOfPages, Info[3].NumberOfPages)); + // Terminator for the list + Info[9].Type = EfiMaxMemoryType; + Info[9].NumberOfPages = 0; + + BuildGuidDataHob (&gEfiMemoryTypeInformationGuid, &Info, sizeof (Info)); +} + +/*++ + +Routine Description: + + + +Arguments: + + FileHandle - Handle of the file being invoked. + PeiServices - Describes the list of possible PEI Services. + +Returns: + + Status - EFI_SUCCESS if the boot mode could be set + +--*/ +EFI_STATUS +EFIAPI +InitializeMemory ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UINTN SystemMemoryBase; + UINTN SystemMemoryTop; + UINTN FdBase; + UINTN FdTop; + UINTN UefiMemoryBase; + + DEBUG ((EFI_D_ERROR, "Memory Init PEIM Loaded\n")); + + // Ensure PcdSystemMemorySize has been set + ASSERT (FixedPcdGet32 (PcdSystemMemorySize) != 0); + + SystemMemoryBase = (UINTN)FixedPcdGet32 (PcdSystemMemoryBase); + SystemMemoryTop = SystemMemoryBase + (UINTN)FixedPcdGet32 (PcdSystemMemorySize); + FdBase = (UINTN)PcdGet32 (PcdFdBaseAddress); + FdTop = FdBase + (UINTN)PcdGet32 (PcdFdSize); + + DEBUG ((EFI_D_ERROR, "SystemMemoryBase : 0x%X, SystemMemoryTop : 0x%X, FdBase : 0x%X, FdTop : 0x%X\n", SystemMemoryBase, SystemMemoryTop, FdBase, FdTop)); + // + // Initialize the System Memory (DRAM) + // + if (!FeaturePcdGet (PcdSystemMemoryInitializeInSec)) { + // In case the DRAM has not been initialized by the secure firmware + ArmPlatformInitializeSystemMemory (); + } + + // + // Declare the UEFI memory to PEI + // + + // In case the firmware has been shadowed in the System Memory + if ((FdBase >= SystemMemoryBase) && (FdTop <= SystemMemoryTop)) { + // Check if there is enough space between the top of the system memory and the top of the + // firmware to place the UEFI memory (for PEI & DXE phases) + if (SystemMemoryTop - FdTop >= FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)) { + UefiMemoryBase = SystemMemoryTop - FixedPcdGet32 (PcdSystemMemoryUefiRegionSize); + } else { + // Check there is enough space for the UEFI memory + ASSERT (SystemMemoryBase + FixedPcdGet32 (PcdSystemMemoryUefiRegionSize) <= FdBase); + + UefiMemoryBase = FdBase - FixedPcdGet32 (PcdSystemMemoryUefiRegionSize); + } + } else { + // Check the Firmware does not overlapped with the system memory + ASSERT ((FdBase < SystemMemoryBase) || (FdBase >= SystemMemoryTop)); + ASSERT ((FdTop <= SystemMemoryBase) || (FdTop > SystemMemoryTop)); + + UefiMemoryBase = SystemMemoryTop - FixedPcdGet32 (PcdSystemMemoryUefiRegionSize); + } + + DEBUG ((EFI_D_ERROR, "UefiMemoryBase : 0x%X, PcdSystemMemoryUefiRegionSize : 0x%X\n", UefiMemoryBase, FixedPcdGet32(PcdSystemMemoryUefiRegionSize))); + Status = PeiServicesInstallPeiMemory (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)); + ASSERT_EFI_ERROR (Status); + + // Initialize MMU and Memory HOBs (Resource Descriptor HOBs) + Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeim.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeim.inf new file mode 100644 index 000000000..23d245ef1 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/MemoryInitPei/MemoryInitPeim.inf @@ -0,0 +1,75 @@ +#/** @file +# +# Copyright (c) 2011, ARM Ltd. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemoryInit + FILE_GUID = c61ef796-b50d-4f98-9f78-4f6f79d800d5 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeMemory + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC ARM +# + +[Sources] + MemoryInitPeim.c + MemoryInitPeiLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + +[LibraryClasses] + PeimEntryPoint + DebugLib + HobLib + ArmLib + ArmPlatformLib + +[Guids] + gEfiMemoryTypeInformationGuid + +[FeaturePcd] + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob + gArmPlatformTokenSpaceGuid.PcdSystemMemoryInitializeInSec + +[FixedPcd] + gArmTokenSpaceGuid.PcdFdBaseAddress + gArmTokenSpaceGuid.PcdFdSize + + gArmTokenSpaceGuid.PcdSystemMemoryBase + gArmTokenSpaceGuid.PcdSystemMemorySize + gArmPlatformTokenSpaceGuid.PcdSystemMemoryUefiRegionSize + + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData + + gExynosPkgTokenSpaceGuid.PcdPmuBase +[Depex] + TRUE diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeiLib.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeiLib.c new file mode 100644 index 000000000..813c1d349 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeiLib.c @@ -0,0 +1,30 @@ +/** @file +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include <PiPei.h> + +#include <Library/ArmPlatformLib.h> +#include <Library/HobLib.h> +#include <Library/PcdLib.h> + +EFI_STATUS +EFIAPI +PlatformPeim ( + VOID + ) +{ + BuildFvHob (PcdGet32(PcdFvBaseAddress), PcdGet32(PcdFvSize)); + + return EFI_SUCCESS; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeiLib.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeiLib.inf new file mode 100644 index 000000000..01f935952 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeiLib.inf @@ -0,0 +1,53 @@ +#/** @file +# +# Copyright (c) 2011-2012, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmPlatformPeiLib + FILE_GUID = 49d37060-70b5-11e0-aa2d-0002a5d5c51b + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformPeiLib + +[Sources] + PlatformPeiLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + +[LibraryClasses] + DebugLib + HobLib + ArmPlatformLib + +[Ppis] + gEfiPeiMasterBootModePpiGuid # PPI ALWAYS_PRODUCED + gEfiPeiBootInRecoveryModePpiGuid # PPI SOMETIMES_PRODUCED + +[FixedPcd] + gArmTokenSpaceGuid.PcdFdBaseAddress + gArmTokenSpaceGuid.PcdFdSize + + gArmTokenSpaceGuid.PcdFvBaseAddress + gArmTokenSpaceGuid.PcdFvSize + + gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize + +[depex] + TRUE diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeim.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeim.c new file mode 100644 index 000000000..8663409ed --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeim.c @@ -0,0 +1,138 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include <PiPei.h> + +// +// The protocols, PPI and GUID defintions for this module +// +#include <Ppi/ArmGlobalVariable.h> +#include <Ppi/MasterBootMode.h> +#include <Ppi/BootInRecoveryMode.h> +#include <Ppi/GuidedSectionExtraction.h> +// +// The Library classes this module consumes +// +#include <Library/ArmPlatformLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/PeimEntryPoint.h> +#include <Library/PeiServicesLib.h> +#include <Library/PcdLib.h> + +#include <Guid/ArmGlobalVariableHob.h> + +EFI_STATUS +EFIAPI +InitializePlatformPeim ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ); + +EFI_STATUS +EFIAPI +PlatformPeim ( + VOID + ); + +// +// Module globals +// +EFI_PEI_PPI_DESCRIPTOR mPpiListBootMode = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiMasterBootModePpiGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiBootInRecoveryModePpiGuid, + NULL +}; + +VOID +EFIAPI +BuildGlobalVariableHob ( + IN EFI_PHYSICAL_ADDRESS GlobalVariableBase, + IN UINT32 GlobalVariableSize + ) +{ + EFI_STATUS Status; + ARM_HOB_GLOBAL_VARIABLE *Hob; + + Status = PeiServicesCreateHob (EFI_HOB_TYPE_GUID_EXTENSION, sizeof (ARM_HOB_GLOBAL_VARIABLE), (VOID**)&Hob); + if (!EFI_ERROR(Status)) { + CopyGuid (&(Hob->Header.Name), &gArmGlobalVariableGuid); + Hob->GlobalVariableBase = GlobalVariableBase; + Hob->GlobalVariableSize = GlobalVariableSize; + } +} + +/*++ + +Routine Description: + + + +Arguments: + + FileHandle - Handle of the file being invoked. + PeiServices - Describes the list of possible PEI Services. + +Returns: + + Status - EFI_SUCCESS if the boot mode could be set + +--*/ +EFI_STATUS +EFIAPI +InitializePlatformPeim ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UINTN BootMode; + ARM_GLOBAL_VARIABLE_PPI *ArmGlobalVariablePpi; + EFI_PHYSICAL_ADDRESS GlobalVariableBase; + + DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n")); + + PlatformPeim (); + + Status = PeiServicesLocatePpi (&gArmGlobalVariablePpiGuid, 0, NULL, (VOID**)&ArmGlobalVariablePpi); + if (!EFI_ERROR(Status)) { + Status = ArmGlobalVariablePpi->GetGlobalVariableMemory (&GlobalVariableBase); + + if (!EFI_ERROR(Status)) { + // Declare the Global Variable HOB + BuildGlobalVariableHob (GlobalVariableBase, FixedPcdGet32 (PcdPeiGlobalVariableSize)); + } + } + + BootMode = ArmPlatformGetBootMode (); + Status = (**PeiServices).SetBootMode (PeiServices, (UINT8) BootMode); + ASSERT_EFI_ERROR (Status); + + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiListBootMode); + ASSERT_EFI_ERROR (Status); + + if (BootMode == BOOT_IN_RECOVERY_MODE) { + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiListRecoveryBootMode); + ASSERT_EFI_ERROR (Status); + } + + return Status; +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeim.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeim.inf new file mode 100755 index 000000000..cd1cd7a51 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/PlatformPei/PlatformPeim.inf @@ -0,0 +1,69 @@ +#/** @file +# +# Copyright (c) 2011-2012, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformPei + FILE_GUID = 2ad0fc59-2314-4bf3-8633-13fa22a624a0 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializePlatformPeim + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC ARM +# + +[Sources] + PlatformPeim.c + PlatformPeiLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + +[LibraryClasses] + PeimEntryPoint + DebugLib + HobLib + ArmPlatformLib + +[Ppis] + gEfiPeiMasterBootModePpiGuid # PPI ALWAYS_PRODUCED + gEfiPeiBootInRecoveryModePpiGuid # PPI SOMETIMES_PRODUCED + gArmGlobalVariablePpiGuid + +[Guids] + gArmGlobalVariableGuid + +[FixedPcd] + gArmTokenSpaceGuid.PcdFdBaseAddress + gArmTokenSpaceGuid.PcdFdSize + + gArmTokenSpaceGuid.PcdFvBaseAddress + gArmTokenSpaceGuid.PcdFvSize + + gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize + + gArmPlatformTokenSpaceGuid.PcdPeiGlobalVariableSize + +[Depex] + TRUE + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Helper.S b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Helper.S new file mode 100644 index 000000000..ad53ab320 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Helper.S @@ -0,0 +1,84 @@ +#======================================================================================== +# Copyright (c) 2011-2012, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http:#opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#======================================================================================= + +#start of the code section +.text +.align 3 + +GCC_ASM_EXPORT(return_from_exception) +GCC_ASM_EXPORT(enter_monitor_mode) +GCC_ASM_EXPORT(copy_cpsr_into_spsr) +GCC_ASM_EXPORT(set_non_secure_mode) + +# r0: Monitor World EntryPoint +# r1: MpId +# r2: Secure Monitor mode stack +ASM_PFX(enter_monitor_mode): + cmp r2, #0 @ If a Secure Monitor stack base has not been defined then use the Secure stack + moveq r2, sp + + mrs r4, cpsr @ Save current mode (SVC) in r4 + bic r3, r4, #0x1f @ Clear all mode bits + orr r3, r3, #0x16 @ Set bits for Monitor mode + msr cpsr_cxsf, r3 @ We are now in Monitor Mode + + mov sp, r2 @ Set the stack of the Monitor Mode + + mov lr, r0 @ Use the pass entrypoint as lr + + msr spsr_cxsf, r4 @ Use saved mode for the MOVS jump to the kernel + + mov r4, r0 @ Swap EntryPoint and MpId registers + mov r0, r1 + + bx r4 + +# We cannot use the instruction 'movs pc, lr' because the caller can be written either in ARM or Thumb2 assembler. +# When we will jump into this function, we will set the CPSR flag to ARM assembler. By copying directly 'lr' into +# 'pc'; we will not change the CPSR flag and it will crash. +# The way to fix this limitation is to do the movs into the ARM assmbler code and then do a 'bx'. +ASM_PFX(return_from_exception): + ldr lr, returned_exception + + #The following instruction breaks the code. + #movs pc, lr + mrs r2, cpsr + bic r2, r2, #0x1f + orr r2, r2, #0x13 + msr cpsr_c, r2 + +returned_exception: @ We are now in non-secure state + bx r0 + +# Save the current Program Status Register (PSR) into the Saved PSR +ASM_PFX(copy_cpsr_into_spsr): + mrs r0, cpsr + msr spsr_cxsf, r0 + bx lr + +# Set the Non Secure Mode +ASM_PFX(set_non_secure_mode): + push { r1 } + and r0, r0, #0x1f @ Keep only the mode bits + mrs r1, spsr @ Read the spsr + bic r1, r1, #0x1f @ Clear all mode bits + orr r1, r1, r0 + msr spsr_cxsf, r1 @ write back spsr (may have caused a mode switch) + isb + pop { r1 } + bx lr @ return (hopefully thumb-safe!) + +dead: + b dead + +ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Helper.asm b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Helper.asm new file mode 100644 index 000000000..c4eaec1a7 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Helper.asm @@ -0,0 +1,75 @@ +// +// Copyright (c) 2011-2012, ARM Limited. All rights reserved. +// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// + + EXPORT return_from_exception + EXPORT enter_monitor_mode + EXPORT copy_cpsr_into_spsr + EXPORT set_non_secure_mode + + AREA Helper, CODE, READONLY + +// r0: Monitor World EntryPoint +// r1: MpId +// r2: Secure Monitor mode stack +enter_monitor_mode + cmp r2, #0 // If a Secure Monitor stack base has not been defined then use the Secure stack + moveq r2, sp + + mrs r4, cpsr // Save current mode (SVC) in r4 + bic r3, r4, #0x1f // Clear all mode bits + orr r3, r3, #0x16 // Set bits for Monitor mode + msr cpsr_cxsf, r3 // We are now in Monitor Mode + + mov sp, r2 // Set the stack of the Monitor Mode + + mov lr, r0 // Use the pass entrypoint as lr + + msr spsr_cxsf, r4 // Use saved mode for the MOVS jump to the kernel + + mov r4, r0 // Swap EntryPoint and MpId registers + mov r0, r1 + + bx r4 + +// We cannot use the instruction 'movs pc, lr' because the caller can be written either in ARM or Thumb2 assembler. +// When we will jump into this function, we will set the CPSR flag to ARM assembler. By copying directly 'lr' into +// 'pc'; we will not change the CPSR flag and it will crash. +// The way to fix this limitation is to do the movs into the ARM assmbler code and then do a 'bx'. +return_from_exception + adr lr, returned_exception + movs pc, lr +returned_exception // We are now in non-secure state + bx r0 + +// Save the current Program Status Register (PSR) into the Saved PSR +copy_cpsr_into_spsr + mrs r0, cpsr + msr spsr_cxsf, r0 + bx lr + +// Set the Non Secure Mode +set_non_secure_mode + push { r1 } + and r0, r0, #0x1f // Keep only the mode bits + mrs r1, spsr // Read the spsr + bic r1, r1, #0x1f // Clear all mode bits + orr r1, r1, r0 + msr spsr_cxsf, r1 // write back spsr (may have caused a mode switch) + isb + pop { r1 } + bx lr // return (hopefully thumb-safe!) + +dead + B dead + + END diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Sec.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Sec.c new file mode 100644 index 000000000..3c4f4983f --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Sec.c @@ -0,0 +1,222 @@ +/** @file +* Main file supporting the SEC Phase on ARM Platforms +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include <Library/ArmTrustedMonitorLib.h> +#include <Library/DebugAgentLib.h> +#include <Library/PrintLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/SerialPortLib.h> +#include <Library/ArmGicLib.h> +#include <Library/ArmCpuLib.h> +#include <Library/IoLib.h> +#include <Library/ArmPlatformLib.h> +#include "SecInternal.h" +#include "Smc.h" + +#define SerialPrint(txt) SerialPortWrite ((UINT8*)txt, AsciiStrLen(txt)+1); + +extern VOID *monitor_vector_table; + +#define ISRAM_ADDRESS 0x02020000 +#define EXTERNAL_FUNC_ADDRESS (ISRAM_ADDRESS + 0x0030) +#define MSH_ReadFromFIFO_eMMC_ADDRESS (EXTERNAL_FUNC_ADDRESS + 0x14) +#define MSH_EndBootOp_eMMC_ADDRESS (EXTERNAL_FUNC_ADDRESS + 0x18) + +#define SDMMC_ReadBlocks(uStartBlk, uNumOfBlks, uDstAddr) \ + (((VOID(*)(UINT32, UINT32, UINT32*))(*((UINT32 *)EXTERNAL_FUNC_ADDRESS)))(uStartBlk, uNumOfBlks, uDstAddr)) + +#define EMMC_ReadBlocks(uNumOfBlks, uDstAddr) \ + (((VOID(*)(UINT32, UINT32*))(*((UINT32 *)MSH_ReadFromFIFO_eMMC_ADDRESS)))(uNumOfBlks, uDstAddr)) + +#define EMMC_EndBootOp() \ + (((VOID(*)())(*((UINT32 *)MSH_EndBootOp_eMMC_ADDRESS)))()) + +VOID CopyFirmwareFromSDMMC(VOID) +{ + SDMMC_ReadBlocks(49, ((1536*1024)/512), (UINT32 *)0x40000000); +} + +VOID CopyFirmwareFromEMMC(VOID) +{ + if (FixedPcdGetBool (PcdTrustzoneSupport)) { + load_uefi_image(EMMC); + } else { + EMMC_ReadBlocks(((1536*1024)/512), (UINT32 *)0x40000000); + EMMC_EndBootOp(); + } +} + +VOID ColdBootForTzsw(UINT32 StartupAddr) +{ + coldboot(EMMC, StartupAddr); +} + +VOID +CEntryPoint ( + IN UINTN MpId + ) +{ + CHAR8 Buffer[100]; + UINTN CharCount; + UINTN JumpAddress; + + if (!FixedPcdGetBool (PcdTrustzoneSupport)) { + // Invalidate the data cache. Doesn't have to do the Data cache clean. + ArmInvalidateDataCache(); + + // Invalidate Instruction Cache + ArmInvalidateInstructionCache(); + + // Invalidate I & D TLBs + ArmInvalidateInstructionAndDataTlb(); + + // CPU specific settings + ArmCpuSetup (MpId); + + // Enable Floating Point Coprocessor if supported by the platform + if (FixedPcdGet32 (PcdVFPEnabled)) { + ArmEnableVFP(); + } + // Initialize peripherals that must be done at the early stage + // Example: Some L2 controller, interconnect, clock, DMC, etc + ArmPlatformSecInitialize (MpId); + } + + // Primary CPU clears out the SCU tag RAMs, secondaries wait + if (ArmPlatformIsPrimaryCore (MpId)) { + if (ArmIsMpCore()) { + // Is UEFI built as it is assumed that TZSW is running? + // PcdTrustzoneSupport==1: YES. + // PcdTrustzoneSupport==1: NO. UEFI is built as it is assumed that TZSW is not needed. + if (FixedPcdGetBool (PcdTrustzoneSupport)) { + // IS UEFI executed after TZSW ran? (In other words, UEFI is fuzed and running? + // ArmReadNsacr()==1: YES. + // ArmReadNsacr()!=1: No. UEFI(assumed TZSW is running) is executed after uploaded with T32(not fuzed) + if(ArmReadNsacr()) { + exynos_smc(SMC_CMD_CPU1BOOT, 0, 0, 0); + } + } + } + + // SEC phase needs to run library constructors by hand. This assumes we are linked against the SerialLib + // In non SEC modules the init call is in autogenerated code. + SerialPortInitialize (); + + // Start talking + if (FixedPcdGetBool (PcdTrustzoneSupport)) { + CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Secure firmware (version %s built at %a on %a)\n\r", + (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); + } else { + CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Boot firmware (version %s built at %a on %a)\n\r", + (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); + } + SerialPortWrite ((UINT8 *) Buffer, CharCount); + + // Initialize the Debug Agent for Source Level Debugging + InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL); + SaveAndSetDebugTimerInterrupt (TRUE); + + // Enable the GIC distributor and CPU Interface + // - no other Interrupts are enabled, doesn't have to worry about the priority. + // - all the cores are in secure state, use secure SGI's + ArmGicEnableDistributor (PcdGet32(PcdGicDistributorBase)); + ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); + + } else { + // Enable the GIC CPU Interface + ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); + } + + // Enable Full Access to CoProcessors + ArmWriteCpacr (CPACR_CP_FULL_ACCESS); + + // With Trustzone support the transition from Sec to Normal world is done by return_from_exception(). + // If we want to keep this function call we need to ensure the SVC's SPSR point to the same Program + // Status Register as the the current one (CPSR). + copy_cpsr_into_spsr (); + + // Call the Platform specific function to execute additional actions if required + JumpAddress = PcdGet32 (PcdFvBaseAddress); + ArmPlatformSecExtraAction (MpId, &JumpAddress); + + NonTrustedWorldTransition (MpId, JumpAddress); + + ASSERT (0); // We must never return from the above function +} + +VOID +TrustedWorldInitialization ( + IN UINTN MpId + ) +{ + UINTN JumpAddress; + + //-------------------- Monitor Mode --------------------- + + // Set up Monitor World (Vector Table, etc) + ArmSecureMonitorWorldInitialize (); + + // Transfer the interrupt to Non-secure World + ArmGicSetupNonSecure (MpId, PcdGet32(PcdGicDistributorBase), PcdGet32(PcdGicInterruptInterfaceBase)); + + // Initialize platform specific security policy + ArmPlatformSecTrustzoneInit (MpId); + + // Setup the Trustzone Chipsets + if (ArmPlatformIsPrimaryCore (MpId)) { + if (ArmIsMpCore()) { + // Signal the secondary core the Security settings is done (event: EVENT_SECURE_INIT) + ArmCallSEV (); + } + } else { + // The secondary cores need to wait until the Trustzone chipsets configuration is done + // before switching to Non Secure World + + // Wait for the Primary Core to finish the initialization of the Secure World (event: EVENT_SECURE_INIT) + ArmCallWFE (); + } + + // Call the Platform specific function to execute additional actions if required + JumpAddress = PcdGet32 (PcdFvBaseAddress); + ArmPlatformSecExtraAction (MpId, &JumpAddress); + + // Write to CP15 Non-secure Access Control Register + ArmWriteNsacr (PcdGet32 (PcdArmNsacr)); + + // CP15 Secure Configuration Register + ArmWriteScr (PcdGet32 (PcdArmScr)); + + NonTrustedWorldTransition (MpId, JumpAddress); +} + +VOID +NonTrustedWorldTransition ( + IN UINTN MpId, + IN UINTN JumpAddress + ) +{ + // If PcdArmNonSecModeTransition is defined then set this specific mode to CPSR before the transition + // By not set, the mode for Non Secure World is SVC + if (PcdGet32 (PcdArmNonSecModeTransition) != 0) { + set_non_secure_mode ((ARM_PROCESSOR_MODE)PcdGet32 (PcdArmNonSecModeTransition)); + } + + return_from_exception (JumpAddress); + //-------------------- Non Secure Mode --------------------- + + // PEI Core should always load and never return + ASSERT (FALSE); +} + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Sec.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Sec.inf new file mode 100644 index 000000000..1cda8c3ad --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Sec.inf @@ -0,0 +1,85 @@ +#/** @file +# SEC - Reset vector code that jumps to C and loads DXE core +# +# Copyright (c) 2011, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmPlatformSec + FILE_GUID = c536bbfe-c813-4e48-9f90-01fe1ecf9d54 + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + +[Sources.ARM] + Helper.asm | RVCT + Helper.S | GCC + Sec.c + SecEntryPoint.S | GCC + SecEntryPoint.asm | RVCT + Smc.c + SecFromTzsw.S | GCC + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec + +[LibraryClasses] + ArmCpuLib + ArmLib + ArmPlatformSecLib + ArmTrustedMonitorLib + BaseLib + DebugLib + DebugAgentLib + IoLib + ArmGicLib + PrintLib + SerialPortLib + +[FeaturePcd] + gArmPlatformTokenSpaceGuid.PcdSystemMemoryInitializeInSec + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString + + gArmTokenSpaceGuid.PcdTrustzoneSupport + gArmTokenSpaceGuid.PcdVFPEnabled + + gArmTokenSpaceGuid.PcdArmScr + gArmTokenSpaceGuid.PcdArmNsacr + gArmTokenSpaceGuid.PcdArmNonSecModeTransition + + gArmTokenSpaceGuid.PcdSecureFvBaseAddress + gArmTokenSpaceGuid.PcdSecureFvSize + + gArmTokenSpaceGuid.PcdFvBaseAddress + gArmTokenSpaceGuid.PcdFdBaseAddress + + gArmPlatformTokenSpaceGuid.PcdCPUCoresSecStackBase + gArmPlatformTokenSpaceGuid.PcdCPUCoreSecPrimaryStackSize + gArmPlatformTokenSpaceGuid.PcdCPUCoreSecSecondaryStackSize + gArmPlatformTokenSpaceGuid.PcdCPUCoresSecMonStackBase + gArmPlatformTokenSpaceGuid.PcdCPUCoreSecMonStackSize + + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + + gArmPlatformTokenSpaceGuid.PcdSecGlobalVariableSize + + gExynosPkgTokenSpaceGuid.PcdMpSharedArgsBase + + gExynosPkgTokenSpaceGuid.PcdiRamStackBase + gExynosPkgTokenSpaceGuid.PcdiRamStackSize diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecEntryPoint.S b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecEntryPoint.S new file mode 100644 index 000000000..aecbc939f --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecEntryPoint.S @@ -0,0 +1,287 @@ +// +// Copyright (c) 2011-2012, ARM Limited. All rights reserved. +// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// + +#include <AutoGen.h> +#include <AsmMacroIoLib.h> +#include <Library/ArmPlatformLib.h> +#include <ArmPlatform.h> +#include "SecInternal.h" + +.text +.align 3 + +GCC_ASM_IMPORT(CEntryPoint) +GCC_ASM_IMPORT(ArmPlatformIsPrimaryCore) +GCC_ASM_IMPORT(CopyFirmwareFromEMMC) +GCC_ASM_IMPORT(CopyFirmwareFromSDMMC) +GCC_ASM_IMPORT(ArmPlatformClockInitialize) +GCC_ASM_IMPORT(ArmPlatformSecBootAction) +GCC_ASM_IMPORT(ArmPlatformSecBootMemoryInit) +GCC_ASM_IMPORT(ArmDisableInterrupts) +GCC_ASM_IMPORT(ArmDisableCachesAndMmu) +GCC_ASM_IMPORT(ArmEnableBranchPrediction) +GCC_ASM_IMPORT(ArmReadMpidr) +GCC_ASM_IMPORT(ArmCallWFE) +GCC_ASM_IMPORT(_SecEntryFromTzsw) +GCC_ASM_EXPORT(_ModuleEntryPoint) + +SecStartupAddr: .word ASM_PFX(_SecEntryFromTzsw) +StartupAddr: .word ASM_PFX(CEntryPoint) + +// Convert the (ClusterId,CoreId) into a Core Position +// 0x0F03 is the magic value for ARM_CORE_MASK | ARM_CLUSTER_MASK +//Core is 0-1 bits and cluster is 8-11 bits +#define GetCorePositionFromMpId(Pos, MpId, Tmp) \ + ldr Tmp, =0x0F03 ; \ + and MpId, Tmp ; \ + lsr Pos, MpId, #6 ; \ + and Tmp, MpId, #3 ; \ + add Pos, Pos, Tmp + +// Reserve a region at the top of the IRAM Core stack +// for Global variables for the XIP phase +#define SetiRamStack(StackTop, GlobalSize, Tmp) \ + and Tmp, GlobalSize, #7 ; \ + rsbne Tmp, Tmp, #8 ; \ + add GlobalSize, GlobalSize, Tmp ; \ + sub sp, StackTop, GlobalSize ; \ + ; \ + mov Tmp, sp ; \ + mov GlobalSize, #0x0 ; \ +_SetiRamStackInitGlobals: ; \ + cmp Tmp, StackTop ; \ + beq _SetiRamStackEnd ; \ + str GlobalSize, [Tmp], #4 ; \ + b _SetiRamStackInitGlobals ; \ +_SetiRamStackEnd: + + +ASM_PFX(_ModuleEntryPoint): + // First ensure all interrupts are disabled + bl ASM_PFX(ArmDisableInterrupts) + + // Ensure that the MMU and caches are off + bl ASM_PFX(ArmDisableCachesAndMmu) + + // Jump to Platform Specific Boot Action function + blx ASM_PFX(ArmPlatformSecBootAction) + + # Enable branch prediction + bl ASM_PFX(ArmEnableBranchPrediction) + + # TZPC1_DECPROT1Set (work-around for connecting T32 in SD booting mode) +// ldr r0, =0x10110810 +// mov r1, #0xF +// str r1, [r0] +// dsb +// isb +// sev + +// ldr r0, =0x1 +// ldr r1, =0x2 +//infloop: +// cmp r0, r1 +// bme infloop + + +_IdentifyCpu: + // Identify CPU ID + bl ASM_PFX(ArmReadMpidr) + // Keep a copy of the MpId register value + mov r5, r0 + + // Is it the Primary Core ? + bl ASM_PFX(ArmPlatformIsPrimaryCore) + cmp r0, #1 + + // Only the primary core initialize the memory (SMC) + beq _InitMem + +_WaitInitMem: + // Wait for the primary core to initialize the initial memory (event: BOOT_MEM_INIT) + bl ASM_PFX(ArmCallWFE) + // Now the Init Mem is initialized, we setup the secondary core stacks + b _SetupSecondaryCoreStack + +_InitMem: + // Initialize Init Boot Memory + mov r0, pc + ldr r1, =0x40000000 + cmp r0, r1 + bgt _SetupPrimaryCoreStack + + bl ASM_PFX(ArmPlatformClockInitialize) + + LoadConstantToReg (FixedPcdGet32(PcdiRamStackBase), r1) + LoadConstantToReg (FixedPcdGet32(PcdiRamStackSize), r2) + + // The reserved space for global variable must be 8-bytes aligned for pushing + // 64-bit variable on the stack + SetiRamStack (r1, r2, r3) + + bl ASM_PFX(ArmPlatformSecBootMemoryInit) + +_SetupPrimaryCoreStack: + // Get the top of the primary stacks (and the base of the secondary stacks) + LoadConstantToReg (FixedPcdGet32(PcdCPUCoresSecStackBase), r1) + LoadConstantToReg (FixedPcdGet32(PcdCPUCoreSecPrimaryStackSize), r2) + add r1, r1, r2 + + LoadConstantToReg (FixedPcdGet32(PcdSecGlobalVariableSize), r2) + + // The reserved space for global variable must be 8-bytes aligned for pushing + // 64-bit variable on the stack + SetPrimaryStack (r1, r2, r3) + + mov r0, pc + ldr r1, =0x40000000 + cmp r0, r1 + bgt _PrepareArguments_NonTZ + + b _CopyFirmware + +_SetupSecondaryCoreStack: + // Get the top of the primary stacks (and the base of the secondary stacks) + LoadConstantToReg (FixedPcdGet32(PcdCPUCoresSecStackBase), r1) + LoadConstantToReg (FixedPcdGet32(PcdCPUCoreSecPrimaryStackSize), r2) + add r1, r1, r2 + + // Get the Core Position (ClusterId * 4) + CoreId + GetCorePositionFromMpId(r0, r5, r2) + // The stack starts at the top of the stack region. Add '1' to the Core Position to get the top of the stack + add r0, r0, #1 + + // StackOffset = CorePos * StackSize + LoadConstantToReg (FixedPcdGet32(PcdCPUCoreSecSecondaryStackSize), r2) + mul r0, r0, r2 + // SP = StackBase + StackOffset + add sp, r1, r0 + + b _PrepareArguments_NonTZ + +_PrepareArguments: + // Move sec startup address into a data register + // Ensure we're jumping to FV version of the code (not boot remapped alias) + LoadConstantToReg (FixedPcdGet32(PcdTrustzoneSupport), r2) + cmp r2, #0x1 /* TrustZone Enable */ + beq _PrepareArguments_TZ + +_PrepareArguments_NonTZ: + ldr r3, StartupAddr + // Jump to SEC C code + // r0 = mp_id + mov r0, r5 + blx r3 + +_PrepareArguments_TZ: + /* Load IRAM_NS on IRAM_NS_BASE */ + /* TZSW will call IRAM_NS code */ + bl relocate_code + + /* Jump to Coldboot in TZSW */ + ldr r0, SecStartupAddr + b _ColdBootTzsw + +_CopyFirmware: + ldr r0, =Exynos5250_CMU_BASE + ldr r2, =CLK_DIV_FSYS2_OFFSET + ldr r1, [r0, r2] + bic r1, r1, #(0xFF << 8) + bic r1, r1, #(0xF) + orr r1, r1, #(0x9<< 8) + orr r1, r1, #0x3 + str r1, [r0, r2] + + /* Read booting information */ + ldr r0, =0x10040000 + ldr r1, [r0,#0x0] + bic r2, r1, #0xffffffc1 + + cmp r2, #0x8 + beq _CopyFirmwareEMMC + + /* SD/MMC BOOT */ + cmp r2, #0x4 + beq _CopyFirmwareSDMMC + + +_CopyFirmwareSDMMC: + bl ASM_PFX(CopyFirmwareFromSDMMC) + b _PrepareArguments + +_CopyFirmwareEMMC: + bl ASM_PFX(CopyFirmwareFromEMMC) + b _PrepareArguments + +_ColdBootTzsw: + bl ASM_PFX(ColdBootForTzsw) +_NeverReturn: + b _NeverReturn + + +/* + * relocate_code: load NonSecure code(cpu1_wait) + */ +relocate_code: + adr r0, nscode_base @ r0: source address (start) + adr r1, nscode_end @ r1: source address (end) + ldr r2, =CONFIG_PHY_IRAM_NS_BASE @ r2: target address + +1: + ldmia r0!, {r3-r6} + stmia r2!, {r3-r6} + cmp r0, r1 + blt 1b + + .word 0xF57FF04F @dsb sy + .word 0xF57FF06F @isb sy + + mov pc, lr + +/* + * CPU1 waits here until CPU0 wake it up. + * - below code is copied to CONFIG_PHY_IRAM_NS_BASE, which is non-secure memory. + */ +nscode_base: + adr r0, _ns_reg5 + b 1f + + .word 0x0 @ REG0: RESUME_ADDR + .word 0x0 @ REG1: RESUME_FLAG + .word 0x0 @ REG2 + .word 0x0 @ REG3 + .word 0x0 @ REG4 +_ns_reg5: + .word 0x0 @ REG5: CPU1_BOOT_REG + .word 0x0 @ REG6: REG_DIRECTGO_FLAG + .word 0x0 @ REG7: REG_DIRECTGO_ADDR + .word 0x0 @ REG8 + .word 0x0 @ REG9 + + nop + nop + +1: +#if 0 /* Exynos5250 do not require this code */ + mrc p15, 0, r1, c0, c0, 5 @ MPIDR + and r1, r1, #0x3 + add r0, r0, r1, lsl #0x2 +#endif +cpu1_wait: + .word 0xE320F002 @ wfe instruction + ldr r1, [r0] + cmp r1, #0x0 + bxne r1 + b cpu1_wait + nop +nscode_end: diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecEntryPoint.asm b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecEntryPoint.asm new file mode 100644 index 000000000..07ad1289b --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecEntryPoint.asm @@ -0,0 +1,112 @@ +// +// Copyright (c) 2011-2012, ARM Limited. All rights reserved. +// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// + +#include <AutoGen.h> +#include <AsmMacroIoLib.h> +#include "SecInternal.h" + + INCLUDE AsmMacroIoLib.inc + + IMPORT CEntryPoint + IMPORT ArmPlatformSecBootAction + IMPORT ArmPlatformSecBootMemoryInit + IMPORT ArmDisableInterrupts + IMPORT ArmDisableCachesAndMmu + IMPORT ArmReadMpidr + IMPORT ArmCallWFE + EXPORT _ModuleEntryPoint + + PRESERVE8 + AREA SecEntryPoint, CODE, READONLY + +StartupAddr DCD CEntryPoint + +_ModuleEntryPoint + // First ensure all interrupts are disabled + blx ArmDisableInterrupts + + // Ensure that the MMU and caches are off + blx ArmDisableCachesAndMmu + + // Jump to Platform Specific Boot Action function + blx ArmPlatformSecBootAction + +_IdentifyCpu + // Identify CPU ID + bl ArmReadMpidr + // Get ID of this CPU in Multicore system + LoadConstantToReg (FixedPcdGet32(PcdArmPrimaryCoreMask), r1) + and r5, r0, r1 + + // Is it the Primary Core ? + LoadConstantToReg (FixedPcdGet32(PcdArmPrimaryCore), r3) + cmp r5, r3 + // Only the primary core initialize the memory (SMC) + beq _InitMem + +_WaitInitMem + // Wait for the primary core to initialize the initial memory (event: BOOT_MEM_INIT) + bl ArmCallWFE + // Now the Init Mem is initialized, we setup the secondary core stacks + b _SetupSecondaryCoreStack + +_InitMem + // Initialize Init Boot Memory + bl ArmPlatformSecBootMemoryInit + + // Only Primary CPU could run this line (the secondary cores have jumped from _IdentifyCpu to _SetupStack) + LoadConstantToReg (FixedPcdGet32(PcdArmPrimaryCore), r5) + +_SetupPrimaryCoreStack + // Get the top of the primary stacks (and the base of the secondary stacks) + LoadConstantToReg (FixedPcdGet32(PcdCPUCoresSecStackBase), r1) + LoadConstantToReg (FixedPcdGet32(PcdCPUCoreSecPrimaryStackSize), r2) + add r1, r1, r2 + + LoadConstantToReg (FixedPcdGet32(PcdSecGlobalVariableSize), r2) + + // The reserved space for global variable must be 8-bytes aligned for pushing + // 64-bit variable on the stack + SetPrimaryStack (r1, r2, r3) + b _PrepareArguments + +_SetupSecondaryCoreStack + // Get the top of the primary stacks (and the base of the secondary stacks) + LoadConstantToReg (FixedPcdGet32(PcdCPUCoresSecStackBase), r1) + LoadConstantToReg (FixedPcdGet32(PcdCPUCoreSecPrimaryStackSize), r2) + add r1, r1, r2 + + // Get the Core Position (ClusterId * 4) + CoreId + GetCorePositionInStack(r0, r5, r2) + // The stack starts at the top of the stack region. Add '1' to the Core Position to get the top of the stack + add r0, r0, #1 + + // StackOffset = CorePos * StackSize + LoadConstantToReg (FixedPcdGet32(PcdCPUCoreSecSecondaryStackSize), r2) + mul r0, r0, r2 + // SP = StackBase + StackOffset + add sp, r1, r0 + +_PrepareArguments + // Move sec startup address into a data register + // Ensure we're jumping to FV version of the code (not boot remapped alias) + ldr r3, StartupAddr + + // Jump to SEC C code + // r0 = mp_id + mov r0, r5 + blx r3 + +_NeverReturn + b _NeverReturn + END diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecFromTzsw.S b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecFromTzsw.S new file mode 100644 index 000000000..aa6a896c9 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecFromTzsw.S @@ -0,0 +1,13 @@ + +.text + +GCC_ASM_IMPORT(CEntryPoint) +GCC_ASM_EXPORT(_SecEntryFromTzsw) + +StartupAddr: .word ASM_PFX(CEntryPoint) + +ASM_PFX(_SecEntryFromTzsw): + mov r0, #0 + ldr r3, StartupAddr + blx r3 + diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecInternal.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecInternal.h new file mode 100644 index 000000000..eff157a64 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/SecInternal.h @@ -0,0 +1,75 @@ +/** @file +* Main file supporting the SEC Phase on ARM PLatforms +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __SEC_H__ +#define __SEC_H__ + +#include <Base.h> +#include <Library/ArmLib.h> +#include <Library/ArmCpuLib.h> +#include <Library/ArmPlatformSecLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <ArmPlatform.h> + +#define IS_ALIGNED(Address, Align) (((UINTN)Address & (Align-1)) == 0) + +VOID +TrustedWorldInitialization ( + IN UINTN MpId + ); + +VOID +NonTrustedWorldTransition ( + IN UINTN MpId, + IN UINTN JumpAddress + ); + +VOID +ArmSetupGicNonSecure ( + IN INTN GicDistributorBase, + IN INTN GicInterruptInterfaceBase +); + +VOID +enter_monitor_mode ( + IN UINTN MonitorEntryPoint, + IN UINTN MpId, + IN VOID* Stack + ); + +VOID +return_from_exception ( + IN UINTN NonSecureBase + ); + +VOID +copy_cpsr_into_spsr ( + VOID + ); + +VOID +set_non_secure_mode ( + IN ARM_PROCESSOR_MODE Mode + ); + +VOID +SecCommonExceptionEntry ( + IN UINT32 Entry, + IN UINT32 LR + ); + +#endif diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Smc.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Smc.c new file mode 100644 index 000000000..3de899a11 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Smc.c @@ -0,0 +1,110 @@ +/** @file +* Main file supporting the SMC call on ARM Platforms +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "Smc.h" + +#define SMC_CMD_LOAD_UEFI (-230) +#define SMC_CMD_COLDBOOT (-231) +#define SMC_CMD_WARMBOOT (-232) + +#define SIGNATURE_SIZE 0 + +#define MOVI_BLKSIZE (1 << 9) +#define PART_SIZE_UEFI (2560 * 1024) +#define PART_SIZE_TZSW (156 * 1024) +#define MOVI_UEFI_BLKCNT (PART_SIZE_UEFI / MOVI_BLKSIZE) +#define MOVI_TZSW_BLKCNT (PART_SIZE_TZSW / MOVI_BLKSIZE) + +typedef struct sdmmc_dev { + /* for SDMMC */ + UINT32 image_pos; + UINT32 blkcnt; + UINT32 base_addr; +} sdmmc_t; + +typedef struct emmc_dev { + /* for eMMC */ + UINT32 blkcnt; + UINT32 base_addr; +} emmc_t; + +/* boot device */ +typedef union boot_device_u { + sdmmc_t sdmmc; + emmc_t emmc; +} boot_device_t; + +typedef struct ld_image_info { + UINT32 image_base_addr; + UINT32 size; + UINT32 secure_context_base; + UINT32 signature_size; + boot_device_t bootdev; +} image_info; + +UINT32 exynos_smc(UINT32 cmd, UINT32 arg1, UINT32 arg2, UINT32 arg3) +{ + register UINT32 reg0 __asm__("r0") = cmd; + register UINT32 reg1 __asm__("r1") = arg1; + register UINT32 reg2 __asm__("r2") = arg2; + register UINT32 reg3 __asm__("r3") = arg3; + + __asm__ volatile ( + ".arch_extension sec\n" + "smc 0\n" + : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3) + + ); + + return reg0; +} + +void load_uefi_image(UINT32 boot_device) +{ + image_info *info_image; + + info_image = (image_info *) CONFIG_IMAGE_INFO_BASE; + + if (boot_device == EMMC) { + info_image->bootdev.emmc.blkcnt = MOVI_UEFI_BLKCNT; + info_image->bootdev.emmc.base_addr = CONFIG_PHY_UEFI_BASE; + } + + info_image->image_base_addr = CONFIG_PHY_UEFI_BASE; + info_image->size = (MOVI_UEFI_BLKCNT * MOVI_BLKSIZE); + info_image->secure_context_base = CONFIG_SECURE_CONTEXT_BASE; + info_image->signature_size = SIGNATURE_SIZE; + + exynos_smc(SMC_CMD_LOAD_UEFI, boot_device, CONFIG_IMAGE_INFO_BASE, 0); +} + +void coldboot(UINT32 boot_device, UINT32 JumpAddress) +{ + image_info *info_image; + + info_image = (image_info *) CONFIG_IMAGE_INFO_BASE; + + if (boot_device == EMMC) { + info_image->bootdev.emmc.blkcnt = MOVI_TZSW_BLKCNT; + info_image->bootdev.emmc.base_addr = CONFIG_PHY_TZSW_BASE; + } + + info_image->image_base_addr = CONFIG_PHY_TZSW_BASE; + info_image->size = (MOVI_TZSW_BLKCNT * MOVI_BLKSIZE); + info_image->secure_context_base = CONFIG_SECURE_CONTEXT_BASE; + info_image->signature_size = SIGNATURE_SIZE; + + exynos_smc(SMC_CMD_COLDBOOT, boot_device, CONFIG_IMAGE_INFO_BASE, JumpAddress); +} diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Smc.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Smc.h new file mode 100644 index 000000000..1dcb1ac79 --- /dev/null +++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Sec/Smc.h @@ -0,0 +1,60 @@ +/** @file +* Header file supporting the SMC call on ARM Platforms +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __SMC_H__ +#define __SMC_H__ + +#include <Platform/ArmPlatform.h> + +/* Boot Device */ +#define SDMMC_CH2 0x0 +#define SDMMC_CH0 0x4 +#define EMMC 0x14 + +/* SMC call define */ +#define SMC_CMD_INIT (-1) +#define SMC_CMD_INFO (-2) +/* For Power Management */ +#define SMC_CMD_SLEEP (-3) +#define SMC_CMD_CPU1BOOT (-4) +#define SMC_CMD_CPU0AFTR (-5) +/* For CP15 Access */ +#define SMC_CMD_C15RESUME (-11) +/* For L2 Cache Access */ +#define SMC_CMD_L2X0CTRL (-21) +#define SMC_CMD_L2X0SETUP1 (-22) +#define SMC_CMD_L2X0SETUP2 (-23) +#define SMC_CMD_L2X0INVALL (-24) +#define SMC_CMD_L2X0DEBUG (-25) + +/* For Accessing CP15/SFR (General) */ +#define SMC_CMD_REG (-101) + +/* MACRO for SMC_CMD_REG */ +#define SMC_REG_CLASS_CP15 (0x0 << 30) +#define SMC_REG_CLASS_SFR_W (0x1 << 30) +#define SMC_REG_CLASS_SFR_R (0x3 << 30) +#define SMC_REG_CLASS_MASK (0x3 << 30) +#define SMC_REG_ID_CP15(CRn, Op1, CRm, Op2) \ + (SMC_REG_CLASS_CP15 | \ + ((CRn) << 10) | ((Op1) << 7) | ((CRm) << 3) | (Op2)) +#define SMC_REG_ID_SFR_W(ADDR) (SMC_REG_CLASS_SFR_W | ((ADDR) >> 2)) +#define SMC_REG_ID_SFR_R(ADDR) (SMC_REG_CLASS_SFR_R | ((ADDR) >> 2)) + +void load_uefi_image(UINT32 boot_device); +void coldboot(UINT32 boot_device, UINT32 JumpAddress); +UINT32 exynos_smc(UINT32 cmd, UINT32 arg1, UINT32 arg2, UINT32 arg3); + +#endif /* __SMC_H__ */ |