diff options
-rw-r--r-- | docs/user-guide.md | 8 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicv3_main.c | 5 | ||||
-rw-r--r-- | drivers/emmc/emmc.c | 75 | ||||
-rw-r--r-- | drivers/io/io_block.c | 64 | ||||
-rw-r--r-- | include/drivers/emmc.h | 6 | ||||
-rw-r--r-- | plat/rockchip/common/pmusram/pmu_sram_cpus_on.S | 2 | ||||
-rw-r--r-- | plat/rockchip/rk3399/drivers/pmu/pmu.c | 120 | ||||
-rw-r--r-- | plat/rockchip/rk3399/drivers/pmu/pmu.h | 22 | ||||
-rw-r--r-- | plat/rockchip/rk3399/drivers/pwm/pwm.c | 147 | ||||
-rw-r--r-- | plat/rockchip/rk3399/drivers/pwm/pwm.h | 37 | ||||
-rw-r--r-- | plat/rockchip/rk3399/drivers/soc/soc.c | 51 | ||||
-rw-r--r-- | plat/rockchip/rk3399/drivers/soc/soc.h | 24 | ||||
-rw-r--r-- | plat/rockchip/rk3399/platform.mk | 2 | ||||
-rw-r--r-- | plat/rockchip/rk3399/rk3399_def.h | 10 | ||||
-rw-r--r-- | tools/fiptool/Makefile | 4 |
15 files changed, 413 insertions, 164 deletions
diff --git a/docs/user-guide.md b/docs/user-guide.md index 8af83773..a6959b14 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -1042,10 +1042,10 @@ This version of the ARM Trusted Firmware has been tested on the following ARM FVPs (64-bit versions only). * `Foundation_Platform` (Version 9.5, Build 9.5.40) -* `FVP_Base_AEMv8A-AEMv8A` (Version 7.2, Build 0.8.7202) -* `FVP_Base_Cortex-A57x4-A53x4` (Version 7.2, Build 0.8.7202) -* `FVP_Base_Cortex-A57x1-A53x1` (Version 7.2, Build 0.8.7202) -* `FVP_Base_Cortex-A57x2-A53x4` (Version 7.2, Build 0.8.7202) +* `FVP_Base_AEMv8A-AEMv8A` (Version 7.6, Build 0.8.7605) +* `FVP_Base_Cortex-A57x4-A53x4` (Version 7.6, Build 0.8.7605) +* `FVP_Base_Cortex-A57x1-A53x1` (Version 7.6, Build 0.8.7605) +* `FVP_Base_Cortex-A57x2-A53x4` (Version 7.6, Build 0.8.7605) NOTE: The build numbers quoted above are those reported by launching the FVP with the `--version` parameter. `Foundation_Platform` tarball for `--version` diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 8cb80203..d13e2c9c 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -284,9 +284,10 @@ void gicv3_cpuif_disable(unsigned int proc_num) write_icc_igrpen0_el1(read_icc_igrpen0_el1() & ~IGRPEN1_EL1_ENABLE_G0_BIT); - /* Disable Group1 Secure interrupts */ + /* Disable Group1 Secure and Non-Secure interrupts */ write_icc_igrpen1_el3(read_icc_igrpen1_el3() & - ~IGRPEN1_EL3_ENABLE_G1S_BIT); + ~(IGRPEN1_EL3_ENABLE_G1NS_BIT | + IGRPEN1_EL3_ENABLE_G1S_BIT)); /* Synchronise accesses to group enable registers */ isb(); diff --git a/drivers/emmc/emmc.c b/drivers/emmc/emmc.c index 5fe28efc..3fae2a15 100644 --- a/drivers/emmc/emmc.c +++ b/drivers/emmc/emmc.c @@ -40,6 +40,12 @@ static const emmc_ops_t *ops; static unsigned int emmc_ocr_value; static emmc_csd_t emmc_csd; +static unsigned int emmc_flags; + +static int is_cmd23_enabled(void) +{ + return (!!(emmc_flags & EMMC_FLAG_CMD23)); +} static int emmc_device_state(void) { @@ -174,11 +180,23 @@ size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size) ret = ops->prepare(lba, buf, size); assert(ret == 0); - memset(&cmd, 0, sizeof(emmc_cmd_t)); - if (size > EMMC_BLOCK_SIZE) + if (is_cmd23_enabled()) { + memset(&cmd, 0, sizeof(emmc_cmd_t)); + /* set block count */ + cmd.cmd_idx = EMMC_CMD23; + cmd.cmd_arg = size / EMMC_BLOCK_SIZE; + cmd.resp_type = EMMC_RESPONSE_R1; + ret = ops->send_cmd(&cmd); + assert(ret == 0); + + memset(&cmd, 0, sizeof(emmc_cmd_t)); cmd.cmd_idx = EMMC_CMD18; - else - cmd.cmd_idx = EMMC_CMD17; + } else { + if (size > EMMC_BLOCK_SIZE) + cmd.cmd_idx = EMMC_CMD18; + else + cmd.cmd_idx = EMMC_CMD17; + } if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) cmd.cmd_arg = lba * EMMC_BLOCK_SIZE; else @@ -193,11 +211,13 @@ size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size) /* wait buffer empty */ emmc_device_state(); - if (size > EMMC_BLOCK_SIZE) { - memset(&cmd, 0, sizeof(emmc_cmd_t)); - cmd.cmd_idx = EMMC_CMD12; - ret = ops->send_cmd(&cmd); - assert(ret == 0); + if (is_cmd23_enabled() == 0) { + if (size > EMMC_BLOCK_SIZE) { + memset(&cmd, 0, sizeof(emmc_cmd_t)); + cmd.cmd_idx = EMMC_CMD12; + ret = ops->send_cmd(&cmd); + assert(ret == 0); + } } /* Ignore improbable errors in release builds */ (void)ret; @@ -218,11 +238,24 @@ size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size) ret = ops->prepare(lba, buf, size); assert(ret == 0); - memset(&cmd, 0, sizeof(emmc_cmd_t)); - if (size > EMMC_BLOCK_SIZE) + if (is_cmd23_enabled()) { + /* set block count */ + memset(&cmd, 0, sizeof(emmc_cmd_t)); + cmd.cmd_idx = EMMC_CMD23; + cmd.cmd_arg = size / EMMC_BLOCK_SIZE; + cmd.resp_type = EMMC_RESPONSE_R1; + ret = ops->send_cmd(&cmd); + assert(ret == 0); + + memset(&cmd, 0, sizeof(emmc_cmd_t)); cmd.cmd_idx = EMMC_CMD25; - else - cmd.cmd_idx = EMMC_CMD24; + } else { + memset(&cmd, 0, sizeof(emmc_cmd_t)); + if (size > EMMC_BLOCK_SIZE) + cmd.cmd_idx = EMMC_CMD25; + else + cmd.cmd_idx = EMMC_CMD24; + } if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) cmd.cmd_arg = lba * EMMC_BLOCK_SIZE; else @@ -237,11 +270,13 @@ size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size) /* wait buffer empty */ emmc_device_state(); - if (size > EMMC_BLOCK_SIZE) { - memset(&cmd, 0, sizeof(emmc_cmd_t)); - cmd.cmd_idx = EMMC_CMD12; - ret = ops->send_cmd(&cmd); - assert(ret == 0); + if (is_cmd23_enabled() == 0) { + if (size > EMMC_BLOCK_SIZE) { + memset(&cmd, 0, sizeof(emmc_cmd_t)); + cmd.cmd_idx = EMMC_CMD12; + ret = ops->send_cmd(&cmd); + assert(ret == 0); + } } /* Ignore improbable errors in release builds */ (void)ret; @@ -328,7 +363,8 @@ size_t emmc_rpmb_erase_blocks(int lba, size_t size) return size_erased; } -void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width) +void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width, + unsigned int flags) { assert((ops_ptr != 0) && (ops_ptr->init != 0) && @@ -342,6 +378,7 @@ void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width) (width == EMMC_BUS_WIDTH_4) || (width == EMMC_BUS_WIDTH_8))); ops = ops_ptr; + emmc_flags = flags; emmc_enumerate(clk, width); } diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c index 198b723b..4ec59bc7 100644 --- a/drivers/io/io_block.c +++ b/drivers/io/io_block.c @@ -198,6 +198,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, io_block_ops_t *ops; size_t aligned_length, skip, count, left, padding, block_size; int lba; + int buffer_not_aligned; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; @@ -208,6 +209,17 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, (length > 0) && (ops->read != 0)); + if ((buffer & (block_size - 1)) != 0) { + /* + * buffer isn't aligned with block size. + * Block device always relies on DMA operation. + * It's better to make the buffer as block size aligned. + */ + buffer_not_aligned = 1; + } else { + buffer_not_aligned = 0; + } + skip = cur->file_pos % block_size; aligned_length = ((skip + length) + (block_size - 1)) & ~(block_size - 1); @@ -216,8 +228,13 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, do { lba = (cur->file_pos + cur->base) / block_size; if (left >= buf->length) { - /* Since left is larger, it's impossible to padding. */ - if (skip) { + /* + * Since left is larger, it's impossible to padding. + * + * If buffer isn't aligned, we need to use aligned + * buffer instead. + */ + if (skip || buffer_not_aligned) { /* * The beginning address (file_pos) isn't * aligned with block size, we need to use @@ -231,10 +248,11 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, } assert(count == buf->length); cur->file_pos += count - skip; - if (skip) { + if (skip || buffer_not_aligned) { /* - * Since it's not aligned with block size, - * block buffer is used to store data. + * Since there's not aligned block size caused + * by skip or not aligned buffer, block buffer + * is used to store data. */ memcpy((void *)buffer, (void *)(buf->offset + skip), @@ -242,13 +260,16 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, } left = left - (count - skip); } else { - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* * The beginning address (file_pos) isn't * aligned with block size, we have to read * full block by block buffer instead. * The size isn't aligned with block size. * Use block buffer to avoid overflow. + * + * If buffer isn't aligned, use block buffer + * to avoid DMA error. */ count = ops->read(lba, buf->offset, left); } else @@ -256,10 +277,10 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, assert(count == left); left = left - (skip + padding); cur->file_pos += left; - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* - * Since it's not aligned with block size, - * block buffer is used to store data. + * Since there's not aligned block size or + * buffer, block buffer is used to store data. */ memcpy((void *)buffer, (void *)(buf->offset + skip), @@ -283,6 +304,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, io_block_ops_t *ops; size_t aligned_length, skip, count, left, padding, block_size; int lba; + int buffer_not_aligned; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; @@ -294,6 +316,17 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, (ops->read != 0) && (ops->write != 0)); + if ((buffer & (block_size - 1)) != 0) { + /* + * buffer isn't aligned with block size. + * Block device always relies on DMA operation. + * It's better to make the buffer as block size aligned. + */ + buffer_not_aligned = 1; + } else { + buffer_not_aligned = 0; + } + skip = cur->file_pos % block_size; aligned_length = ((skip + length) + (block_size - 1)) & ~(block_size - 1); @@ -303,12 +336,12 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, lba = (cur->file_pos + cur->base) / block_size; if (left >= buf->length) { /* Since left is larger, it's impossible to padding. */ - if (skip) { + if (skip || buffer_not_aligned) { /* * The beginning address (file_pos) isn't - * aligned with block size, we need to use - * block buffer to write block. Since block - * device is always relied on DMA operation. + * aligned with block size or buffer isn't + * aligned, we need to use block buffer to + * write block. */ count = ops->read(lba, buf->offset, buf->length); @@ -324,7 +357,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, cur->file_pos += count - skip; left = left - (count - skip); } else { - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* * The beginning address (file_pos) isn't * aligned with block size, we need to avoid @@ -332,6 +365,9 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, * skipping the beginning is the only way. * The size isn't aligned with block size. * Use block buffer to avoid overflow. + * + * If buffer isn't aligned, use block buffer + * to avoid DMA error. */ count = ops->read(lba, buf->offset, left); assert(count == left); diff --git a/include/drivers/emmc.h b/include/drivers/emmc.h index 61d44959..5f78dcef 100644 --- a/include/drivers/emmc.h +++ b/include/drivers/emmc.h @@ -49,6 +49,7 @@ #define EMMC_CMD13 13 #define EMMC_CMD17 17 #define EMMC_CMD18 18 +#define EMMC_CMD23 23 #define EMMC_CMD24 24 #define EMMC_CMD25 25 #define EMMC_CMD35 35 @@ -111,6 +112,8 @@ #define EMMC_STATE_BTST 9 #define EMMC_STATE_SLP 10 +#define EMMC_FLAG_CMD23 (1 << 0) + typedef struct emmc_cmd { unsigned int cmd_idx; unsigned int cmd_arg; @@ -177,6 +180,7 @@ size_t emmc_erase_blocks(int lba, size_t size); size_t emmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size); size_t emmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size); size_t emmc_rpmb_erase_blocks(int lba, size_t size); -void emmc_init(const emmc_ops_t *ops, int clk, int bus_width); +void emmc_init(const emmc_ops_t *ops, int clk, int bus_width, + unsigned int flags); #endif /* __EMMC_H__ */ diff --git a/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S b/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S index 3378272c..9f94b0c1 100644 --- a/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S +++ b/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S @@ -70,9 +70,7 @@ sys_resume: psram_data: .quad PSRAM_DT_BASE sys_wakeup_entry: -#if !ERROR_DEPRECATED .quad psci_entrypoint -#endif pmu_cpuson_entrypoint_end: .word 0 endfunc pmu_cpuson_entrypoint diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c index 72d71bf7..01f84e92 100644 --- a/plat/rockchip/rk3399/drivers/pmu/pmu.c +++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c @@ -45,6 +45,8 @@ #include <soc.h> #include <pmu.h> #include <pmu_com.h> +#include <pwm.h> +#include <soc.h> DEFINE_BAKERY_LOCK(rockchip_pd_lock); @@ -775,6 +777,36 @@ static void sys_slp_config(void) mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_GPIO_WKUP_EN)); mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg); + /* + * About to switch PMU counters to 32K; switch all timings to 32K + * for simplicity even if we don't plan on using them. + */ + mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_SCU_B_PWRDN_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_SCU_B_PWRUP_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_CENTER_PWRDN_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_CENTER_PWRUP_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_OSC_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_DDRIO_PWRON_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_PLLRST_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_STABLE_CNT, CYCL_32K_CNT_MS(3)); + + mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(PMU_24M_EN_CFG)); + + mmio_write_32(PMU_BASE + PMU_PLL_CON, PLL_PD_HW); + mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON0, EXTERNAL_32K); + mmio_write_32(PMUGRF_BASE, IOMUX_CLK_32K); /* 32k iomux */ +} + +static void sys_slp_unconfig(void) +{ + /* + * About to switch PMU counters to 24M; switch all timings to 24M + * for simplicity even if we don't plan on using them. + */ mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_SCU_B_PWRDN_CNT, CYCL_24M_CNT_MS(3)); @@ -782,16 +814,13 @@ static void sys_slp_config(void) mmio_write_32(PMU_BASE + PMU_CENTER_PWRDN_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_CENTER_PWRUP_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_CNT, CYCL_24M_CNT_MS(3)); - mmio_write_32(PMU_BASE + PMU_OSC_CNT, CYCL_32K_CNT_MS(3)); + mmio_write_32(PMU_BASE + PMU_OSC_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_DDRIO_PWRON_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_PLLRST_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_STABLE_CNT, CYCL_24M_CNT_MS(3)); - mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(PMU_24M_EN_CFG)); - mmio_write_32(PMU_BASE + PMU_PLL_CON, PLL_PD_HW); - mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON0, EXTERNAL_32K); - mmio_write_32(PMUGRF_BASE, IOMUX_CLK_32K); /*32k iomux*/ + mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(PMU_24M_EN_CFG)); } static void set_hw_idle(uint32_t hw_idle) @@ -804,72 +833,6 @@ static void clr_hw_idle(uint32_t hw_idle) mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle); } -struct pwm_data_s pwm_data; - -/* - * Save the PWMs data. - */ -static void save_pwms(void) -{ - uint32_t i; - - pwm_data.iomux_bitmask = 0; - - /* Save all IOMUXes */ - if (mmio_read_32(GRF_BASE + GRF_GPIO4C_IOMUX) & GPIO4C2_IOMUX_PWM) - pwm_data.iomux_bitmask |= PWM0_IOMUX_PWM_EN; - if (mmio_read_32(GRF_BASE + GRF_GPIO4C_IOMUX) & GPIO4C6_IOMUX_PWM) - pwm_data.iomux_bitmask |= PWM1_IOMUX_PWM_EN; - if (mmio_read_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX) & - GPIO1C3_IOMUX_PWM) - pwm_data.iomux_bitmask |= PWM2_IOMUX_PWM_EN; - if (mmio_read_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX) & - GPIO0A6_IOMUX_PWM) - pwm_data.iomux_bitmask |= PWM3_IOMUX_PWM_EN; - - for (i = 0; i < 4; i++) { - /* Save cnt, period, duty and ctrl for PWM i */ - pwm_data.cnt[i] = mmio_read_32(PWM_BASE + PWM_CNT(i)); - pwm_data.duty[i] = mmio_read_32(PWM_BASE + PWM_PERIOD_HPR(i)); - pwm_data.period[i] = mmio_read_32(PWM_BASE + PWM_DUTY_LPR(i)); - pwm_data.ctrl[i] = mmio_read_32(PWM_BASE + PWM_CTRL(i)); - } - - /* PWMs all IOMUXes switch to the gpio mode */ - mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, GPIO4C2_IOMUX_GPIO); - mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, GPIO4C6_IOMUX_GPIO); - mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX, GPIO1C3_IOMUX_GPIO); - mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, GPIO0A6_IOMUX_GPIO); -} - -/* - * Restore the PWMs data. - */ -static void restore_pwms(void) -{ - uint32_t i; - - /* Restore all IOMUXes */ - if (pwm_data.iomux_bitmask & PWM3_IOMUX_PWM_EN) - mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, - GPIO0A6_IOMUX_PWM); - if (pwm_data.iomux_bitmask & PWM2_IOMUX_PWM_EN) - mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX, - GPIO1C3_IOMUX_PWM); - if (pwm_data.iomux_bitmask & PWM1_IOMUX_PWM_EN) - mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, GPIO4C6_IOMUX_PWM); - if (pwm_data.iomux_bitmask & PWM0_IOMUX_PWM_EN) - mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, GPIO4C2_IOMUX_PWM); - - for (i = 0; i < 4; i++) { - /* Restore ctrl, duty, period and cnt for PWM i */ - mmio_write_32(PWM_BASE + PWM_CTRL(i), pwm_data.ctrl[i]); - mmio_write_32(PWM_BASE + PWM_DUTY_LPR(i), pwm_data.period[i]); - mmio_write_32(PWM_BASE + PWM_PERIOD_HPR(i), pwm_data.duty[i]); - mmio_write_32(PWM_BASE + PWM_CNT(i), pwm_data.cnt[i]); - } -} - static int sys_pwr_domain_suspend(void) { uint32_t wait_cnt = 0; @@ -916,7 +879,10 @@ static int sys_pwr_domain_suspend(void) } mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN)); - save_pwms(); + plls_suspend_prepare(); + disable_dvfs_plls(); + disable_pwms(); + disable_nodvfs_plls(); return 0; } @@ -926,9 +892,14 @@ static int sys_pwr_domain_resume(void) uint32_t wait_cnt = 0; uint32_t status = 0; - restore_pwms(); + enable_nodvfs_plls(); + enable_pwms(); + /* PWM regulators take time to come up; give 300us to be safe. */ + udelay(300); + enable_dvfs_plls(); + plls_resume_finish(); - pmu_sgrf_rst_hld(); + sys_slp_unconfig(); mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1), (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) | @@ -964,6 +935,7 @@ static int sys_pwr_domain_resume(void) } } + pmu_sgrf_rst_hld_release(); pmu_scu_b_pwrup(); pmu_power_domains_resume(); diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h index ddb1c166..c821efc0 100644 --- a/plat/rockchip/rk3399/drivers/pmu/pmu.h +++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h @@ -812,16 +812,13 @@ enum pmu_core_pwr_st { #define PMUGRF_GPIO1A_IOMUX 0x10 #define PMUGRF_GPIO1C_IOMUX 0x18 +#define PMUGRF_GPIO0A6_IOMUX_SHIFT 12 +#define PMUGRF_GPIO0A6_IOMUX_PWM 0x1 +#define PMUGRF_GPIO1C3_IOMUX_SHIFT 6 +#define PMUGRF_GPIO1C3_IOMUX_PWM 0x1 + #define AP_PWROFF 0x0a -#define GPIO0A6_IOMUX_GPIO BITS_WITH_WMASK(0, 3, 12) -#define GPIO0A6_IOMUX_PWM BITS_WITH_WMASK(1, 3, 12) -#define GPIO1C3_IOMUX_GPIO BITS_WITH_WMASK(0, 3, 6) -#define GPIO1C3_IOMUX_PWM BITS_WITH_WMASK(1, 3, 6) -#define GPIO4C2_IOMUX_GPIO BITS_WITH_WMASK(0, 3, 4) -#define GPIO4C2_IOMUX_PWM BITS_WITH_WMASK(1, 3, 4) -#define GPIO4C6_IOMUX_GPIO BITS_WITH_WMASK(0, 3, 12) -#define GPIO4C6_IOMUX_PWM BITS_WITH_WMASK(1, 3, 12) #define GPIO1A6_IOMUX BITS_WITH_WMASK(0, 3, 12) #define TSADC_INT_PIN 38 @@ -913,15 +910,6 @@ enum pmu_core_pwr_st { mmio_write_32(base + CPU_AXI_QOS_EXTCONTROL, array[6]); \ } while (0) -/* there are 4 PWMs on rk3399 */ -struct pwm_data_s { - uint32_t iomux_bitmask; - uint64_t cnt[4]; - uint64_t duty[4]; - uint64_t period[4]; - uint64_t ctrl[4]; -}; - struct pmu_slpdata_s { uint32_t cci_m0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t cci_m1_qos[CPU_AXI_QOS_NUM_REGS]; diff --git a/plat/rockchip/rk3399/drivers/pwm/pwm.c b/plat/rockchip/rk3399/drivers/pwm/pwm.c new file mode 100644 index 00000000..7845c631 --- /dev/null +++ b/plat/rockchip/rk3399/drivers/pwm/pwm.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <plat_private.h> +#include <pmu.h> +#include <pwm.h> +#include <soc.h> + +#define PWM0_IOMUX_PWM_EN (1 << 0) +#define PWM1_IOMUX_PWM_EN (1 << 1) +#define PWM2_IOMUX_PWM_EN (1 << 2) +#define PWM3_IOMUX_PWM_EN (1 << 3) + +struct pwm_data_s { + uint32_t iomux_bitmask; + uint32_t enable_bitmask; +}; + +static struct pwm_data_s pwm_data; + +/* + * Disable the PWMs. + */ +void disable_pwms(void) +{ + uint32_t i, val; + + pwm_data.iomux_bitmask = 0; + + /* Save PWMs pinmux and change PWMs pinmux to GPIOs */ + val = mmio_read_32(GRF_BASE + GRF_GPIO4C_IOMUX); + if (((val >> GRF_GPIO4C2_IOMUX_SHIFT) & + GRF_IOMUX_2BIT_MASK) == GRF_GPIO4C2_IOMUX_PWM) { + pwm_data.iomux_bitmask |= PWM0_IOMUX_PWM_EN; + val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK, + GRF_GPIO4C2_IOMUX_SHIFT); + mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val); + } + + val = mmio_read_32(GRF_BASE + GRF_GPIO4C_IOMUX); + if (((val >> GRF_GPIO4C6_IOMUX_SHIFT) & + GRF_IOMUX_2BIT_MASK) == GRF_GPIO4C6_IOMUX_PWM) { + pwm_data.iomux_bitmask |= PWM1_IOMUX_PWM_EN; + val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK, + GRF_GPIO4C6_IOMUX_SHIFT); + mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val); + } + + val = mmio_read_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX); + if (((val >> PMUGRF_GPIO1C3_IOMUX_SHIFT) & + GRF_IOMUX_2BIT_MASK) == PMUGRF_GPIO1C3_IOMUX_PWM) { + pwm_data.iomux_bitmask |= PWM2_IOMUX_PWM_EN; + val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK, + PMUGRF_GPIO1C3_IOMUX_SHIFT); + mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX, val); + } + + val = mmio_read_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX); + if (((val >> PMUGRF_GPIO0A6_IOMUX_SHIFT) & + GRF_IOMUX_2BIT_MASK) == PMUGRF_GPIO0A6_IOMUX_PWM) { + pwm_data.iomux_bitmask |= PWM3_IOMUX_PWM_EN; + val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK, + PMUGRF_GPIO0A6_IOMUX_SHIFT); + mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, val); + } + + /* Disable the pwm channel */ + pwm_data.enable_bitmask = 0; + for (i = 0; i < 4; i++) { + val = mmio_read_32(PWM_BASE + PWM_CTRL(i)); + if ((val & PWM_ENABLE) != PWM_ENABLE) + continue; + pwm_data.enable_bitmask |= (1 << i); + mmio_write_32(PWM_BASE + PWM_CTRL(i), val & ~PWM_ENABLE); + } +} + +/* + * Enable the PWMs. + */ +void enable_pwms(void) +{ + uint32_t i, val; + + for (i = 0; i < 4; i++) { + val = mmio_read_32(PWM_BASE + PWM_CTRL(i)); + if (!(pwm_data.enable_bitmask & (1 << i))) + continue; + mmio_write_32(PWM_BASE + PWM_CTRL(i), val | PWM_ENABLE); + } + + /* Restore all IOMUXes */ + if (pwm_data.iomux_bitmask & PWM3_IOMUX_PWM_EN) { + val = BITS_WITH_WMASK(PMUGRF_GPIO0A6_IOMUX_PWM, + GRF_IOMUX_2BIT_MASK, + PMUGRF_GPIO0A6_IOMUX_SHIFT); + mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, val); + } + + if (pwm_data.iomux_bitmask & PWM2_IOMUX_PWM_EN) { + val = BITS_WITH_WMASK(PMUGRF_GPIO1C3_IOMUX_PWM, + GRF_IOMUX_2BIT_MASK, + PMUGRF_GPIO1C3_IOMUX_SHIFT); + mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX, val); + } + + if (pwm_data.iomux_bitmask & PWM1_IOMUX_PWM_EN) { + val = BITS_WITH_WMASK(GRF_GPIO4C6_IOMUX_PWM, + GRF_IOMUX_2BIT_MASK, + GRF_GPIO4C6_IOMUX_SHIFT); + mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val); + } + + if (pwm_data.iomux_bitmask & PWM0_IOMUX_PWM_EN) { + val = BITS_WITH_WMASK(GRF_GPIO4C2_IOMUX_PWM, + GRF_IOMUX_2BIT_MASK, + GRF_GPIO4C2_IOMUX_SHIFT); + mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val); + } +} diff --git a/plat/rockchip/rk3399/drivers/pwm/pwm.h b/plat/rockchip/rk3399/drivers/pwm/pwm.h new file mode 100644 index 00000000..0f75a8de --- /dev/null +++ b/plat/rockchip/rk3399/drivers/pwm/pwm.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PWM_H__ +#define __PWM_H__ + +void disable_pwms(void); +void enable_pwms(void); + +#endif diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c index 9ccf90c4..29bf6dda 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.c +++ b/plat/rockchip/rk3399/drivers/soc/soc.c @@ -236,7 +236,22 @@ static void _pll_suspend(uint32_t pll_id) set_pll_bypass(pll_id); } -void plls_suspend(void) +void disable_dvfs_plls(void) +{ + _pll_suspend(CPLL_ID); + _pll_suspend(NPLL_ID); + _pll_suspend(VPLL_ID); + _pll_suspend(GPLL_ID); + _pll_suspend(ABPLL_ID); + _pll_suspend(ALPLL_ID); +} + +void disable_nodvfs_plls(void) +{ + _pll_suspend(PPLL_ID); +} + +void plls_suspend_prepare(void) { uint32_t i, pll_id; @@ -251,14 +266,6 @@ void plls_suspend(void) slp_data.pmucru_clksel_con[i] = mmio_read_32(PMUCRU_BASE + PMUCRU_CLKSEL_OFFSET + i * REG_SIZE); - - _pll_suspend(CPLL_ID); - _pll_suspend(NPLL_ID); - _pll_suspend(VPLL_ID); - _pll_suspend(PPLL_ID); - _pll_suspend(GPLL_ID); - _pll_suspend(ABPLL_ID); - _pll_suspend(ALPLL_ID); } void clk_gate_con_save(void) @@ -308,7 +315,13 @@ static void set_plls_nobypass(uint32_t pll_id) PLL_NO_BYPASS_MODE); } -static void plls_resume_prepare(void) +static void _pll_resume(uint32_t pll_id) +{ + set_plls_nobypass(pll_id); + set_pll_normal_mode(pll_id); +} + +void plls_resume_finish(void) { int i; @@ -321,15 +334,19 @@ static void plls_resume_prepare(void) REG_SOC_WMSK | slp_data.pmucru_clksel_con[i]); } -void plls_resume(void) +void enable_dvfs_plls(void) { - int pll_id; + _pll_resume(ALPLL_ID); + _pll_resume(ABPLL_ID); + _pll_resume(GPLL_ID); + _pll_resume(VPLL_ID); + _pll_resume(NPLL_ID); + _pll_resume(CPLL_ID); +} - plls_resume_prepare(); - for (pll_id = ALPLL_ID; pll_id < END_PLL_ID; pll_id++) { - set_plls_nobypass(pll_id); - set_pll_normal_mode(pll_id); - } +void enable_nodvfs_plls(void) +{ + _pll_resume(PPLL_ID); } void soc_global_soft_reset_init(void) diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h index 26c0df67..1ea6e5e1 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.h +++ b/plat/rockchip/rk3399/drivers/soc/soc.h @@ -240,6 +240,22 @@ struct deepsleep_data_s { #define CPU_BOOT_ADDR_WMASK 0xffff0000 #define CPU_BOOT_ADDR_ALIGN 16 +#define GRF_IOMUX_2BIT_MASK 0x3 +#define GRF_IOMUX_GPIO 0x0 + +#define GRF_GPIO4C2_IOMUX_SHIFT 4 +#define GRF_GPIO4C2_IOMUX_PWM 0x1 +#define GRF_GPIO4C6_IOMUX_SHIFT 12 +#define GRF_GPIO4C6_IOMUX_PWM 0x1 + +#define PWM_CNT(n) (0x0000 + 0x10 * (n)) +#define PWM_PERIOD_HPR(n) (0x0004 + 0x10 * (n)) +#define PWM_DUTY_LPR(n) (0x0008 + 0x10 * (n)) +#define PWM_CTRL(n) (0x000c + 0x10 * (n)) + +#define PWM_DISABLE (0 << 0) +#define PWM_ENABLE (1 << 0) + /* * When system reset in running state, we want the cpus to be reboot * from maskrom (system reboot), @@ -263,8 +279,12 @@ static inline void pmu_sgrf_rst_hld(void) /* funciton*/ void __dead2 soc_global_soft_reset(void); -void plls_resume(void); -void plls_suspend(void); +void plls_suspend_prepare(void); +void disable_dvfs_plls(void); +void disable_nodvfs_plls(void); +void plls_resume_finish(void); +void enable_dvfs_plls(void); +void enable_nodvfs_plls(void); void clk_gate_con_save(void); void clk_gate_con_disable(void); void clk_gate_con_restore(void); diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk index a3bb426c..94992f6b 100644 --- a/plat/rockchip/rk3399/platform.mk +++ b/plat/rockchip/rk3399/platform.mk @@ -38,6 +38,7 @@ PLAT_INCLUDES := -I${RK_PLAT_COMMON}/ \ -I${RK_PLAT_COMMON}/drivers/pmu/ \ -I${RK_PLAT_SOC}/ \ -I${RK_PLAT_SOC}/drivers/pmu/ \ + -I${RK_PLAT_SOC}/drivers/pwm/ \ -I${RK_PLAT_SOC}/drivers/soc/ \ -I${RK_PLAT_SOC}/include/ \ @@ -74,6 +75,7 @@ BL31_SOURCES += ${RK_GIC_SOURCES} ${RK_PLAT_SOC}/plat_sip_calls.c \ ${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c \ ${RK_PLAT_SOC}/drivers/pmu/pmu.c \ + ${RK_PLAT_SOC}/drivers/pwm/pwm.c \ ${RK_PLAT_SOC}/drivers/soc/soc.c ENABLE_PLAT_COMPAT := 0 diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h index 787ec0cb..8ee71a88 100644 --- a/plat/rockchip/rk3399/rk3399_def.h +++ b/plat/rockchip/rk3399/rk3399_def.h @@ -161,14 +161,4 @@ #define RK3399_G1S_IRQS ARM_IRQ_SEC_PHY_TIMER #define RK3399_G0_IRQS ARM_IRQ_SEC_SGI_6 -#define PWM0_IOMUX_PWM_EN (1 << 0) -#define PWM1_IOMUX_PWM_EN (1 << 1) -#define PWM2_IOMUX_PWM_EN (1 << 2) -#define PWM3_IOMUX_PWM_EN (1 << 3) - -#define PWM_CNT(n) 0x0000 + 0x10 * n -#define PWM_PERIOD_HPR(n) 0x0004 + 0x10 * n -#define PWM_DUTY_LPR(n) 0x0008 + 0x10 * n -#define PWM_CTRL(n) 0x000c + 0x10 * n - #endif /* __PLAT_DEF_H__ */ diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile index ec9dd993..3bc372a2 100644 --- a/tools/fiptool/Makefile +++ b/tools/fiptool/Makefile @@ -68,8 +68,8 @@ ${PROJECT}: ${OBJECTS} Makefile @${ECHO_BLANK_LINE} fip_create: fip_create.sh - mkdir -p ../fip_create - install -m 755 fip_create.sh ../fip_create/fip_create + ${Q}mkdir -p ../fip_create + ${Q}install -m 755 fip_create.sh ../fip_create/fip_create %.o: %.c %.h ${COPIED_H_FILES} Makefile @echo " CC $<" |