nsekar@codeaurora.org has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/29962
Change subject: qcs405: clock: Adding the clock support for qcs405 ......................................................................
qcs405: clock: Adding the clock support for qcs405
Add basic clock support and enable UART, SPI clocks.
Change-Id: I991bdde5f69e1c0f6ec5d6961275a1c077bc5bae Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org Signed-off-by: Pranav Agrawal pranava@codeaurora.org Signed-off-by: Sricharan R sricharan@codeaurora.org --- M src/soc/qualcomm/qcs405/Makefile.inc M src/soc/qualcomm/qcs405/bootblock.c A src/soc/qualcomm/qcs405/clock.c A src/soc/qualcomm/qcs405/include/soc/clock.h 4 files changed, 367 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/62/29962/1
diff --git a/src/soc/qualcomm/qcs405/Makefile.inc b/src/soc/qualcomm/qcs405/Makefile.inc index 6fc87c7..58a62fa 100644 --- a/src/soc/qualcomm/qcs405/Makefile.inc +++ b/src/soc/qualcomm/qcs405/Makefile.inc @@ -7,6 +7,7 @@ bootblock-y += mmu.c bootblock-y += timer.c bootblock-y += gpio.c +bootblock-y += clock.c bootblock-$(CONFIG_DRIVERS_UART) += uart_bitbang.c bootblock-$(CONFIG_QC_SOC_SIMULATE) += flash_controller.c
@@ -22,6 +23,7 @@ romstage-y += cbmem.c romstage-y += timer.c romstage-y += gpio.c +romstage-y += clock.c romstage-y += mmu.c romstage-$(CONFIG_DRIVERS_UART) += uart_bitbang.c romstage-$(CONFIG_QC_SOC_SIMULATE) += flash_controller.c @@ -32,6 +34,7 @@ ramstage-y += cbmem.c ramstage-y += timer.c ramstage-y += gpio.c +ramstage-y += clock.c ramstage-$(CONFIG_DRIVERS_UART) += uart_bitbang.c ramstage-$(CONFIG_QC_SOC_SIMULATE) += flash_controller.c
diff --git a/src/soc/qualcomm/qcs405/bootblock.c b/src/soc/qualcomm/qcs405/bootblock.c index 5e63f13..15d1c18 100644 --- a/src/soc/qualcomm/qcs405/bootblock.c +++ b/src/soc/qualcomm/qcs405/bootblock.c @@ -15,6 +15,12 @@
#include <bootblock_common.h> #include <soc/mmu.h> +#include <soc/clock.h> + +void bootblock_soc_early_init(void) +{ + clock_init(); +}
void bootblock_soc_init(void) { diff --git a/src/soc/qualcomm/qcs405/clock.c b/src/soc/qualcomm/qcs405/clock.c new file mode 100644 index 0000000..6307259 --- /dev/null +++ b/src/soc/qualcomm/qcs405/clock.c @@ -0,0 +1,208 @@ + /* This file is part of the coreboot project. + * + * Copyright 2018 Qualcomm Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include <arch/io.h> +#include <types.h> +#include <console/console.h> +#include <delay.h> +#include <timer.h> +#include <timestamp.h> +#include <commonlib/helpers.h> +#include <string.h> + +#include <soc/clock.h> + +#define DIV(div) (div ? (2*div - 1) : 0) +#define HALF_DIVIDER(div2x) (div2x ? (div2x - 1) : 0) + +struct clock_config uart_cfg[] = { + { + .hz = 1843200, + .hw_ctl = 0x0, + .src = SRC_GPLL0_MAIN_800MHZ, + .div = DIV(0), + .m = 36, + .n = 15625, + .d_2 = 15625, + }, + { + .hz = 3686400, + .hw_ctl = 0x0, + .src = SRC_GPLL0_MAIN_800MHZ, + .div = DIV(0), + .m = 72, + .n = 15625, + .d_2 = 15625, + } +}; + +struct clock_config i2c_cfg[] = { + { + .hz = 19200000, + .hw_ctl = 0x0, + .src = SRC_XO_19_2MHZ, + .div = DIV(0), + }, + { + .hz = 50000000, + .hw_ctl = 0x0, + .src = SRC_GPLL0_MAIN_800MHZ, + .div = DIV(32), + } +}; + +struct clock_config spi_cfg[] = { + { + .hz = 19200000, + .hw_ctl = 0x0, + .src = SRC_XO_19_2MHZ, + .div = DIV(0), + }, + { + .hz = 30000000, + .hw_ctl = 0x0, + .src = SRC_XO_19_2MHZ, + .div = DIV(0), + }, + { + .hz = 50000000, + .hw_ctl = 0x0, + .src = SRC_GPLL0_MAIN_800MHZ, + .div = DIV(32), + } +}; + + +static struct qcs405_clock *const blsp1_uart2_clk = + (void *)GCC_BLSP1_UART2_BASE; + +static struct qcs405_clock *const blsp2_qup0_spi_clk = + (void *)GCC_BLSP2_QUP0_SPI_BASE; + +static int clock_configure_mnd(struct qcs405_clock *clk, uint32_t m, uint32_t n, + uint32_t d_2) +{ + uint32_t reg_val; + + /* Configure Root Clock Generator(RCG) for Dual Edge Mode */ + reg_val = read32(&clk->cfg_rcgr); + reg_val |= (2 << CLK_CTL_CFG_MODE_SHFT); + write32(&clk->cfg_rcgr, reg_val); + + /* Set M/N/D config */ + write32(&clk->m, m & CLK_CTL_RCG_MND_BMSK); + write32(&clk->n, ~(n-m) & CLK_CTL_RCG_MND_BMSK); + write32(&clk->d_2, ~(d_2) & CLK_CTL_RCG_MND_BMSK); + + return 0; +} + +static int clock_configure(struct qcs405_clock *clk, + struct clock_config *clk_cfg, + uint32_t hz, uint32_t num_perfs) +{ + uint32_t reg_val; + uint32_t idx; + + for (idx = 0; idx < num_perfs; idx++) + if (hz <= clk_cfg[idx].hz) + break; + + reg_val = (clk_cfg[idx].src << CLK_CTL_CFG_SRC_SEL_SHFT) | + (clk_cfg[idx].div << CLK_CTL_CFG_SRC_DIV_SHFT); + + /* Set clock config */ + write32(&clk->cfg_rcgr, reg_val); + + if (clk_cfg[idx].m != 0) + clock_configure_mnd(clk, clk_cfg[idx].m, clk_cfg[idx].n, + clk_cfg[idx].d_2); + + /* Commit config to RCG*/ + setbits_le32(&clk->cmd_rcgr, BIT(CLK_CTL_CMD_UPDATE_SHFT)); + + return 0; +} + +static bool clock_is_off(void *cbcr_addr) +{ + return (read32(cbcr_addr) & CLK_CTL_CBC_CLK_OFF_BMSK); +} + +static int clock_enable_vote(void *cbcr_addr, void *vote_addr, + uint32_t vote_bit) +{ + + /* Set clock vote bit */ + setbits_le32(vote_addr, BIT(vote_bit)); + + /* Ensure clock is enabled */ + while (clock_is_off(cbcr_addr)) + ; + + return 0; +} + +static int clock_enable(void *cbcr_addr) +{ + + /* Set clock enable bit */ + setbits_le32(cbcr_addr, BIT(CLK_CTL_CBC_CLK_EN_SHFT)); + + /* Ensure clock is enabled */ + while (clock_is_off(cbcr_addr)) + ; + + return 0; +} + +static int clock_disable(void *cbcr_addr) +{ + + /* Set clock enable bit */ + clrbits_le32(cbcr_addr, BIT(CLK_CTL_CBC_CLK_EN_SHFT)); + return 0; +} + +int clock_reset_bcr(void *bcr_addr, bool reset) +{ + struct qcs405_bcr *bcr = bcr_addr; + + if (reset) + setbits_le32(&bcr->bcr, BIT(CLK_CTL_BCR_BLK_ARES_SHFT)); + else + clrbits_le32(&bcr->bcr, BIT(CLK_CTL_BCR_BLK_ARES_SHFT)); + + return 0; +} + +void clock_init(void) +{ + + clock_configure(blsp1_uart2_clk, uart_cfg, 1843200, + ARRAY_SIZE(uart_cfg)); + + clock_disable(REG(GCC_BLSP1_UART0_APPS_CBCR)); + clock_enable(REG(GCC_BLSP1_UART0_APPS_CBCR)); + clock_enable(REG(GCC_BLSP1_UART2_APPS_CBCR)); + clock_enable_vote(REG(GCC_BLSP1_AHB_CBCR), + REG(GCC_APCS_CLOCK_BRANCH_ENA_VOTE), + BLSP1_AHB_CLK_ENA); + + clock_configure(blsp2_qup0_spi_clk, spi_cfg, 50000000, + ARRAY_SIZE(spi_cfg)); + clock_enable(REG(GCC_BLSP2_QUP0_SPI_APPS_CBCR)); + +} + diff --git a/src/soc/qualcomm/qcs405/include/soc/clock.h b/src/soc/qualcomm/qcs405/include/soc/clock.h new file mode 100644 index 0000000..aa8bbe5 --- /dev/null +++ b/src/soc/qualcomm/qcs405/include/soc/clock.h @@ -0,0 +1,150 @@ + /* This file is part of the coreboot project. + * + * Copyright 2018 Qualcomm Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __SOC_QUALCOMM_QCS405_CLOCK_H__ +#define __SOC_QUALCOMM_QCS405_CLOCK_H__ + +#define GCC_APCS_CLOCK_BRANCH_ENA_VOTE 0x01845004 + +#define GCC_BLSP1_UART0_BASE 0x180600C +#define GCC_BLSP1_UART1_BASE 0x1802044 +#define GCC_BLSP1_UART2_BASE 0x1803034 +#define GCC_BLSP1_UART3_BASE 0x1804014 +#define GCC_BLSP2_UART0_BASE 0x180C044 + +#define GCC_BLSP1_QUP0_SPI_BASE 0x1806034 +#define GCC_BLSP1_QUP1_SPI_BASE 0x1802024 +#define GCC_BLSP1_QUP2_SPI_BASE 0x1803014 +#define GCC_BLSP1_QUP3_SPI_BASE 0x1804024 +#define GCC_BLSP1_QUP4_SPI_BASE 0x1805024 +#define GCC_BLSP2_QUP0_SPI_BASE 0x180C024 + +#define GCC_BLSP1_QUP0_I2C_BASE 0x180602C +#define GCC_BLSP1_QUP1_I2C_BASE 0x180200C +#define GCC_BLSP1_QUP2_I2C_BASE 0x1803000 +#define GCC_BLSP1_QUP3_I2C_BASE 0x1804000 +#define GCC_BLSP1_QUP4_I2C_BASE 0x1805000 +#define GCC_BLSP2_QUP0_I2C_BASE 0x180C00C + +#define GCC_BLSP1_UART0_APPS_CBCR 0x1806004 +#define GCC_BLSP1_UART1_APPS_CBCR 0x180203C +#define GCC_BLSP1_UART2_APPS_CBCR 0x180302C +#define GCC_BLSP1_UART3_APPS_CBCR 0x180400C +#define GCC_BLSP2_UART0_APPS_CBCR 0x180C03C + +#define GCC_BLSP2_QUP0_SPI_APPS_CBCR 0x180C004 + +#define GCC_BLSP1_AHB_CBCR 0x1801008 +#define GCC_BLSP2_AHB_CBCR 0x180B008 + +#define BLSP1_AHB_CLK_ENA 10 +#define BLSP2_AHB_CLK_ENA 20 + + + +#define SRC_XO_19_2MHZ 0 +#define SRC_GPLL0_MAIN_800MHZ 1 + + + +#define GCC_APCS_CLOCK_BRANCH_ENA_VOTE_1 0x0015200C +#define SRC_XO_19_2MHZ 0 +#define REG(addr) ((void *)addr) + +/** + * USB BCR registers + */ +#define GCC_USB_HS_PHY_CFG_AHB_BCR 0x1841038 +#define GCC_USB_HS_BCR 0x1841000 +#define GCC_USB_30_BCR 0x1839000 +#define GCC_USB2A_PHY_BCR 0x1841028 +#define GCC_USB2_HS_PHY_ONLY_BCR 0x1841034 +#define GCC_QUSB2_PHY_BCR 0x184103C + +struct qcs405_clock { + uint32_t cmd_rcgr; + uint32_t cfg_rcgr; + uint32_t m; + uint32_t n; + uint32_t d_2; +}; + +struct qcs405_bcr { + uint32_t bcr; +}; + +struct mdss_clock_config { + const char *clk_name; + struct qcs405_clock *rcgr; + uint32_t *cbcr; +}; + +enum clk_ctl_gpll_user_ctl { + CLK_CTL_GPLL_PLLOUT_EVEN_BMSK = 0x2, + CLK_CTL_GPLL_PLLOUT_EVEN_SHFT = 1 +}; + +enum clk_ctl_cfg_rcgr { + CLK_CTL_CFG_HW_CTL_BMSK = 0x100000, + CLK_CTL_CFG_HW_CTL_SHFT = 20, + CLK_CTL_CFG_MODE_BMSK = 0x3000, + CLK_CTL_CFG_MODE_SHFT = 12, + CLK_CTL_CFG_SRC_SEL_BMSK = 0x700, + CLK_CTL_CFG_SRC_SEL_SHFT = 8, + CLK_CTL_CFG_SRC_DIV_BMSK = 0x1F, + CLK_CTL_CFG_SRC_DIV_SHFT = 0 +}; + +enum clk_ctl_cmd_rcgr { + CLK_CTL_CMD_ROOT_OFF_BMSK = 0x80000000, + CLK_CTL_CMD_ROOT_OFF_SHFT = 31, + CLK_CTL_CMD_ROOT_EN_BMSK = 0x2, + CLK_CTL_CMD_ROOT_EN_SHFT = 1, + CLK_CTL_CMD_UPDATE_BMSK = 0x1, + CLK_CTL_CMD_UPDATE_SHFT = 0 +}; + +enum clk_ctl_cbcr { + CLK_CTL_CBC_CLK_OFF_BMSK = 0x80000000, + CLK_CTL_CBC_CLK_OFF_SHFT = 31, + CLK_CTL_CBC_CLK_EN_BMSK = 0x1, + CLK_CTL_CBC_CLK_EN_SHFT = 0 +}; + +enum clk_ctl_rcg_mnd { + CLK_CTL_RCG_MND_BMSK = 0xFFFF, + CLK_CTL_RCG_MND_SHFT = 0, +}; + +enum clk_ctl_bcr { + CLK_CTL_BCR_BLK_ARES_BMSK = 0x1, + CLK_CTL_BCR_BLK_ARES_SHFT = 0, +}; + +struct clock_config { + uint32_t hz; + uint32_t hw_ctl; + uint32_t src; + uint32_t div; + uint32_t m; + uint32_t n; + uint32_t d_2; +}; + +void clock_init(void); +void clock_reset_aop(void); +int clock_configure_qspi(uint32_t hz); +int clock_reset_bcr(void *bcr_addr, bool reset); + +#endif // __SOC_QUALCOMM_QCS405_CLOCK_H__