arm-trusted-firmware/plat/imx/common/imx_clock.c

156 lines
3.7 KiB
C
Raw Normal View History

imx: imx_clock: Add driver and associated clock register definitions This commit: - Defines a clock stub with a conjoined header defining the clock memory map. - Defines the CCM Clock Gating Register which comes in a quadrumvirate register set to read, set, clear and toggle individual clock gates into one of four states based bitmask. 00: Domain clocks not needed 01: Domain clocks needed when in RUN 10: Domain clocks needed when in RUN and WAIT 11: Domain clocks needed all the time - Defines clock control register bits There are various quadrumvirate register blocks target-root, misc-root, post-root, pre-root in the CCM. The number of registers is huge but the four registers in each quadrumvirate block contain the same bits, so the number of bit definitions is actually quite low. - Defines clock identifiers An array of clock gates is provided in the CCM block. In order to index that array and thus enable/disable clock gates for the right components, we need to provide meaningful names to the indices. Section 5.2.5 of the i.MX7 Solo Application Processor Reference Manual Rev 0.1 provides the relevant details. - Defines target mux select bits This is a comprehensive definition of the target clock mux select bits. These bits are required to correctly select the clock source. Defining all of the bits up-front even for unused blocks in ATF means we can switch on any block we want at a later date without having to write new code in the clock-mux layer. - Defines identifier indices into root-slice array The root-slice array of control registers has a specific set of indices, which differ from the clock-gate indices. - Provides a clock gate enable/disable routine Provides a clock-gate enable/disable routine via the set/clr registers in a given clock-gate control register block. This index passed should be one of the enums associated with CCM and depending on enable/disable being passed either set or clr will be written to. The Domain0 bits are currently the only bits targeted by this write, more work may need to be done on the domain bits in subsequent patches as a result. - imx: Adds set/clr routines to clock layer Adds a set and clr routine to the clock layer. These routines allow us to access the set and clear registers of the "target" block registers. These are the registers where we select the clock source from the available list. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
2018-05-25 16:48:39 +01:00
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
imx: imx_clock: Add driver and associated clock register definitions This commit: - Defines a clock stub with a conjoined header defining the clock memory map. - Defines the CCM Clock Gating Register which comes in a quadrumvirate register set to read, set, clear and toggle individual clock gates into one of four states based bitmask. 00: Domain clocks not needed 01: Domain clocks needed when in RUN 10: Domain clocks needed when in RUN and WAIT 11: Domain clocks needed all the time - Defines clock control register bits There are various quadrumvirate register blocks target-root, misc-root, post-root, pre-root in the CCM. The number of registers is huge but the four registers in each quadrumvirate block contain the same bits, so the number of bit definitions is actually quite low. - Defines clock identifiers An array of clock gates is provided in the CCM block. In order to index that array and thus enable/disable clock gates for the right components, we need to provide meaningful names to the indices. Section 5.2.5 of the i.MX7 Solo Application Processor Reference Manual Rev 0.1 provides the relevant details. - Defines target mux select bits This is a comprehensive definition of the target clock mux select bits. These bits are required to correctly select the clock source. Defining all of the bits up-front even for unused blocks in ATF means we can switch on any block we want at a later date without having to write new code in the clock-mux layer. - Defines identifier indices into root-slice array The root-slice array of control registers has a specific set of indices, which differ from the clock-gate indices. - Provides a clock gate enable/disable routine Provides a clock-gate enable/disable routine via the set/clr registers in a given clock-gate control register block. This index passed should be one of the enums associated with CCM and depending on enable/disable being passed either set or clr will be written to. The Domain0 bits are currently the only bits targeted by this write, more work may need to be done on the domain bits in subsequent patches as a result. - imx: Adds set/clr routines to clock layer Adds a set and clr routine to the clock layer. These routines allow us to access the set and clear registers of the "target" block registers. These are the registers where we select the clock source from the available list. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
2018-05-25 16:48:39 +01:00
#include <stdint.h>
#include <stdbool.h>
#include <arch.h>
#include <lib/mmio.h>
imx: imx_clock: Add driver and associated clock register definitions This commit: - Defines a clock stub with a conjoined header defining the clock memory map. - Defines the CCM Clock Gating Register which comes in a quadrumvirate register set to read, set, clear and toggle individual clock gates into one of four states based bitmask. 00: Domain clocks not needed 01: Domain clocks needed when in RUN 10: Domain clocks needed when in RUN and WAIT 11: Domain clocks needed all the time - Defines clock control register bits There are various quadrumvirate register blocks target-root, misc-root, post-root, pre-root in the CCM. The number of registers is huge but the four registers in each quadrumvirate block contain the same bits, so the number of bit definitions is actually quite low. - Defines clock identifiers An array of clock gates is provided in the CCM block. In order to index that array and thus enable/disable clock gates for the right components, we need to provide meaningful names to the indices. Section 5.2.5 of the i.MX7 Solo Application Processor Reference Manual Rev 0.1 provides the relevant details. - Defines target mux select bits This is a comprehensive definition of the target clock mux select bits. These bits are required to correctly select the clock source. Defining all of the bits up-front even for unused blocks in ATF means we can switch on any block we want at a later date without having to write new code in the clock-mux layer. - Defines identifier indices into root-slice array The root-slice array of control registers has a specific set of indices, which differ from the clock-gate indices. - Provides a clock gate enable/disable routine Provides a clock-gate enable/disable routine via the set/clr registers in a given clock-gate control register block. This index passed should be one of the enums associated with CCM and depending on enable/disable being passed either set or clr will be written to. The Domain0 bits are currently the only bits targeted by this write, more work may need to be done on the domain bits in subsequent patches as a result. - imx: Adds set/clr routines to clock layer Adds a set and clr routine to the clock layer. These routines allow us to access the set and clear registers of the "target" block registers. These are the registers where we select the clock source from the available list. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
2018-05-25 16:48:39 +01:00
#include <imx_regs.h>
#include <imx_clock.h>
void imx_clock_target_set(unsigned int id, uint32_t val)
{
struct ccm *ccm = ((struct ccm *)CCM_BASE);
uintptr_t addr;
if (id > CCM_ROOT_CTRL_NUM)
return;
addr = (uintptr_t)&ccm->ccm_root_ctrl[id].ccm_target_root;
mmio_write_32(addr, val);
}
void imx_clock_target_clr(unsigned int id, uint32_t val)
{
struct ccm *ccm = ((struct ccm *)CCM_BASE);
uintptr_t addr;
if (id > CCM_ROOT_CTRL_NUM)
return;
addr = (uintptr_t)&ccm->ccm_root_ctrl[id].ccm_target_root_clr;
mmio_write_32(addr, val);
}
void imx_clock_gate_enable(unsigned int id, bool enable)
{
struct ccm *ccm = ((struct ccm *)CCM_BASE);
uintptr_t addr;
if (id > CCM_CLK_GATE_CTRL_NUM)
return;
/* TODO: add support for more than DOMAIN0 clocks */
if (enable)
addr = (uintptr_t)&ccm->ccm_clk_gate_ctrl[id].ccm_ccgr_set;
else
addr = (uintptr_t)&ccm->ccm_clk_gate_ctrl[id].ccm_ccgr_clr;
mmio_write_32(addr, CCM_CCGR_SETTING0_DOM_CLK_ALWAYS);
}
void imx_clock_enable_uart(unsigned int uart_id, uint32_t uart_clk_en_bits)
{
unsigned int ccm_trgt_id = CCM_TRT_ID_UART1_CLK_ROOT + uart_id;
unsigned int ccm_ccgr_id = CCM_CCGR_ID_UART1 + uart_id;
/* Check for error */
if (uart_id > MXC_MAX_UART_NUM)
return;
/* Set target register values */
imx_clock_target_set(ccm_trgt_id, uart_clk_en_bits);
/* Enable the clock gate */
imx_clock_gate_enable(ccm_ccgr_id, true);
}
void imx_clock_disable_uart(unsigned int uart_id)
{
unsigned int ccm_trgt_id = CCM_TRT_ID_UART1_CLK_ROOT + uart_id;
unsigned int ccm_ccgr_id = CCM_CCGR_ID_UART1 + uart_id;
/* Check for error */
if (uart_id > MXC_MAX_UART_NUM)
return;
/* Disable the clock gate */
imx_clock_gate_enable(ccm_ccgr_id, false);
/* Clear the target */
imx_clock_target_clr(ccm_trgt_id, 0xFFFFFFFF);
}
void imx_clock_enable_usdhc(unsigned int usdhc_id, uint32_t usdhc_clk_en_bits)
{
unsigned int ccm_trgt_id = CCM_TRT_ID_USDHC1_CLK_ROOT + usdhc_id;
unsigned int ccm_ccgr_id = CCM_CCGR_ID_USBHDC1 + usdhc_id;
/* Check for error */
if (usdhc_id > MXC_MAX_USDHC_NUM)
return;
/* Set target register values */
imx_clock_target_set(ccm_trgt_id, usdhc_clk_en_bits);
/* Enable the clock gate */
imx_clock_gate_enable(ccm_ccgr_id, true);
}
void imx_clock_enable_wdog(unsigned int wdog_id)
{
unsigned int ccm_ccgr_id = CCM_CCGR_ID_WDOG1 + wdog_id;
/* Check for error */
if (wdog_id > MXC_MAX_WDOG_NUM)
return;
/* Enable the clock gate */
imx_clock_gate_enable(ccm_ccgr_id, true);
}
void imx_clock_disable_wdog(unsigned int wdog_id)
{
unsigned int ccm_trgt_id = CCM_TRT_ID_WDOG_CLK_ROOT;
unsigned int ccm_ccgr_id = CCM_CCGR_ID_WDOG1 + wdog_id;
/* Check for error */
if (wdog_id > MXC_MAX_WDOG_NUM)
return;
/* Disable the clock gate */
imx_clock_gate_enable(ccm_ccgr_id, false);
/* Clear the target */
imx_clock_target_clr(ccm_trgt_id, 0xFFFFFFFF);
}
void imx_clock_set_wdog_clk_root_bits(uint32_t wdog_clk_root_en_bits)
{
/* Enable the common clock root just once */
imx_clock_target_set(CCM_TRT_ID_WDOG_CLK_ROOT, wdog_clk_root_en_bits);
}
void imx_clock_enable_usb(unsigned int ccm_ccgr_usb_id)
{
/* Enable the clock gate */
imx_clock_gate_enable(ccm_ccgr_usb_id, true);
}
void imx_clock_disable_usb(unsigned int ccm_ccgr_usb_id)
{
/* Disable the clock gate */
imx_clock_gate_enable(ccm_ccgr_usb_id, false);
}
void imx_clock_set_usb_clk_root_bits(uint32_t usb_clk_root_en_bits)
{
/* Enable the common clock root just once */
imx_clock_target_set(CCM_TRT_ID_USB_HSIC_CLK_ROOT, usb_clk_root_en_bits);
}