summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/imx233/clkctrl-imx233.c
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2011-12-03 15:34:40 +0000
committerAmaury Pouly <pamaury@rockbox.org>2011-12-03 15:34:40 +0000
commitdd865bcd1ef03b32df1bd65508e991d0ae9e5f63 (patch)
tree9bf2a25ba8e960f7beb36b24124cce50b6a7dfe8 /firmware/target/arm/imx233/clkctrl-imx233.c
parent66c53d528f7707b7ce11ba4db56a3085fe7a3d69 (diff)
downloadrockbox-dd865bcd1ef03b32df1bd65508e991d0ae9e5f63.tar.gz
rockbox-dd865bcd1ef03b32df1bd65508e991d0ae9e5f63.zip
imx233: add control for more clocks, add debug clock debug screen
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31121 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/imx233/clkctrl-imx233.c')
-rw-r--r--firmware/target/arm/imx233/clkctrl-imx233.c245
1 files changed, 242 insertions, 3 deletions
diff --git a/firmware/target/arm/imx233/clkctrl-imx233.c b/firmware/target/arm/imx233/clkctrl-imx233.c
index 31fccd3e3b..fa94f23a0f 100644
--- a/firmware/target/arm/imx233/clkctrl-imx233.c
+++ b/firmware/target/arm/imx233/clkctrl-imx233.c
@@ -23,7 +23,7 @@
#define __CLK_CLKGATE (1 << 31)
#define __CLK_BUSY (1 << 29)
-void imx233_enable_xtal_clock(enum imx233_xtal_clkt_t xtal_clk, bool enable)
+void imx233_enable_xtal_clock(enum imx233_xtal_clk_t xtal_clk, bool enable)
{
if(enable)
__REG_CLR(HW_CLKCTRL_XTAL) = xtal_clk;
@@ -31,6 +31,11 @@ void imx233_enable_xtal_clock(enum imx233_xtal_clkt_t xtal_clk, bool enable)
__REG_SET(HW_CLKCTRL_XTAL) = xtal_clk;
}
+bool imx233_is_xtal_clock_enable(enum imx233_xtal_clk_t clk)
+{
+ return HW_CLKCTRL_XTAL & clk;
+}
+
void imx233_enable_clock(enum imx233_clock_t clk, bool enable)
{
volatile uint32_t *REG;
@@ -55,6 +60,20 @@ void imx233_enable_clock(enum imx233_clock_t clk, bool enable)
}
}
+bool imx233_is_clock_enable(enum imx233_clock_t clk)
+{
+ volatile uint32_t *REG;
+ switch(clk)
+ {
+ case CLK_PLL: return HW_CLKCTRL_PLLCTRL0 & HW_CLKCTRL_PLLCTRL0__POWER;
+ case CLK_PIX: REG = &HW_CLKCTRL_PIX; break;
+ case CLK_SSP: REG = &HW_CLKCTRL_SSP; break;
+ default: return true;
+ }
+
+ return !((*REG) & __CLK_CLKGATE);
+}
+
void imx233_set_clock_divisor(enum imx233_clock_t clk, int div)
{
switch(clk)
@@ -74,24 +93,57 @@ void imx233_set_clock_divisor(enum imx233_clock_t clk, int div)
__REG_SET(HW_CLKCTRL_CPU) = div;
while(HW_CLKCTRL_CPU & HW_CLKCTRL_CPU__BUSY_REF_CPU);
break;
- case CLK_AHB:
- __REG_CLR(HW_CLKCTRL_HBUS) = HW_CLKCTRL_HBUS__DIV_BM;
+ case CLK_EMI:
+ __REG_CLR(HW_CLKCTRL_EMI) = HW_CLKCTRL_EMI__DIV_EMI_BM;
+ __REG_SET(HW_CLKCTRL_EMI) = div;
+ while(HW_CLKCTRL_EMI & HW_CLKCTRL_EMI__BUSY_REF_EMI);
+ break;
+ case CLK_HBUS:
+ __REG_CLR(HW_CLKCTRL_HBUS) = HW_CLKCTRL_HBUS__DIV_BM | HW_CLKCTRL_HBUS__DIV_FRAC_EN;
__REG_SET(HW_CLKCTRL_HBUS) = div;
while(HW_CLKCTRL_HBUS & __CLK_BUSY);
break;
+ case CLK_XBUS:
+ __REG_CLR(HW_CLKCTRL_XBUS) = HW_CLKCTRL_XBUS__DIV_BM;
+ __REG_SET(HW_CLKCTRL_XBUS) = div;
+ while(HW_CLKCTRL_XBUS & __CLK_BUSY);
+ break;
default: return;
}
}
+int imx233_get_clock_divisor(enum imx233_clock_t clk)
+{
+ switch(clk)
+ {
+ case CLK_PIX: return __XTRACT(HW_CLKCTRL_PIX, DIV);
+ case CLK_SSP: return __XTRACT(HW_CLKCTRL_SSP, DIV);
+ case CLK_CPU: return __XTRACT(HW_CLKCTRL_CPU, DIV_CPU);
+ case CLK_EMI: return __XTRACT(HW_CLKCTRL_EMI, DIV_EMI);
+ case CLK_HBUS:
+ if(HW_CLKCTRL_HBUS & HW_CLKCTRL_HBUS__DIV_FRAC_EN)
+ return 0;
+ else
+ return __XTRACT(HW_CLKCTRL_HBUS, DIV);
+ case CLK_XBUS: return __XTRACT(HW_CLKCTRL_XBUS, DIV);
+ default: return 0;
+ }
+}
+
void imx233_set_fractional_divisor(enum imx233_clock_t clk, int fracdiv)
{
/* NOTE: HW_CLKCTRL_FRAC only support byte access ! */
volatile uint8_t *REG;
switch(clk)
{
+ case CLK_HBUS:
+ __REG_CLR(HW_CLKCTRL_HBUS) = HW_CLKCTRL_HBUS__DIV_BM;
+ __REG_SET(HW_CLKCTRL_HBUS) = fracdiv | HW_CLKCTRL_HBUS__DIV_FRAC_EN;
+ return;
case CLK_PIX: REG = &HW_CLKCTRL_FRAC_PIX; break;
case CLK_IO: REG = &HW_CLKCTRL_FRAC_IO; break;
case CLK_CPU: REG = &HW_CLKCTRL_FRAC_CPU; break;
+ case CLK_EMI: REG = &HW_CLKCTRL_FRAC_EMI; break;
default: return;
}
@@ -101,6 +153,30 @@ void imx233_set_fractional_divisor(enum imx233_clock_t clk, int fracdiv)
*REG = HW_CLKCTRL_FRAC_XX__CLKGATEXX;;
}
+int imx233_get_fractional_divisor(enum imx233_clock_t clk)
+{
+ /* NOTE: HW_CLKCTRL_FRAC only support byte access ! */
+ volatile uint8_t *REG;
+ switch(clk)
+ {
+ case CLK_HBUS:
+ if(HW_CLKCTRL_HBUS & HW_CLKCTRL_HBUS__DIV_FRAC_EN)
+ return __XTRACT(HW_CLKCTRL_HBUS, DIV);
+ else
+ return 0;
+ case CLK_PIX: REG = &HW_CLKCTRL_FRAC_PIX; break;
+ case CLK_IO: REG = &HW_CLKCTRL_FRAC_IO; break;
+ case CLK_CPU: REG = &HW_CLKCTRL_FRAC_CPU; break;
+ case CLK_EMI: REG = &HW_CLKCTRL_FRAC_EMI; break;
+ default: return 0;
+ }
+
+ if((*REG) & HW_CLKCTRL_FRAC_XX__CLKGATEXX)
+ return 0;
+ else
+ return *REG & ~HW_CLKCTRL_FRAC_XX__XX_STABLE;
+}
+
void imx233_set_bypass_pll(enum imx233_clock_t clk, bool bypass)
{
uint32_t msk;
@@ -109,6 +185,7 @@ void imx233_set_bypass_pll(enum imx233_clock_t clk, bool bypass)
case CLK_PIX: msk = HW_CLKCTRL_CLKSEQ__BYPASS_PIX; break;
case CLK_SSP: msk = HW_CLKCTRL_CLKSEQ__BYPASS_SSP; break;
case CLK_CPU: msk = HW_CLKCTRL_CLKSEQ__BYPASS_CPU; break;
+ case CLK_EMI: msk = HW_CLKCTRL_CLKSEQ__BYPASS_EMI; break;
default: return;
}
@@ -118,6 +195,21 @@ void imx233_set_bypass_pll(enum imx233_clock_t clk, bool bypass)
__REG_CLR(HW_CLKCTRL_CLKSEQ) = msk;
}
+bool imx233_get_bypass_pll(enum imx233_clock_t clk)
+{
+ uint32_t msk;
+ switch(clk)
+ {
+ case CLK_PIX: msk = HW_CLKCTRL_CLKSEQ__BYPASS_PIX; break;
+ case CLK_SSP: msk = HW_CLKCTRL_CLKSEQ__BYPASS_SSP; break;
+ case CLK_CPU: msk = HW_CLKCTRL_CLKSEQ__BYPASS_CPU; break;
+ case CLK_EMI: msk = HW_CLKCTRL_CLKSEQ__BYPASS_EMI; break;
+ default: return false;
+ }
+
+ return HW_CLKCTRL_CLKSEQ & msk;
+}
+
void imx233_enable_usb_pll(bool enable)
{
if(enable)
@@ -126,3 +218,150 @@ void imx233_enable_usb_pll(bool enable)
__REG_CLR(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS;
}
+bool imx233_is_usb_pll_enable(void)
+{
+ return HW_CLKCTRL_PLLCTRL0 & HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS;
+}
+
+void imx233_set_auto_slow_divisor(enum imx233_as_div_t div)
+{
+ __REG_CLR(HW_CLKCTRL_HBUS) = HW_CLKCTRL_HBUS__SLOW_DIV_BM;
+ __REG_SET(HW_CLKCTRL_HBUS) = div;
+}
+
+enum imx233_as_div_t imx233_get_auto_slow_divisor(void)
+{
+ return __XTRACT(HW_CLKCTRL_HBUS, SLOW_DIV);
+}
+
+void imx233_enable_auto_slow(bool enable)
+{
+ if(enable)
+ __REG_CLR(HW_CLKCTRL_HBUS) = HW_CLKCTRL_HBUS__AUTO_SLOW_MODE;
+ else
+ __REG_SET(HW_CLKCTRL_HBUS) = HW_CLKCTRL_HBUS__AUTO_SLOW_MODE;
+}
+
+bool imx233_is_auto_slow_enable(void)
+{
+ return HW_CLKCTRL_HBUS & HW_CLKCTRL_HBUS__AUTO_SLOW_MODE;
+}
+
+void imx233_enable_auto_slow_monitor(enum imx233_as_monitor_t monitor, bool enable)
+{
+ if(enable)
+ __REG_SET(HW_CLKCTRL_HBUS) = monitor;
+ else
+ __REG_CLR(HW_CLKCTRL_HBUS) = monitor;
+}
+
+bool imx233_is_auto_slow_monitor_enable(enum imx233_as_monitor_t monitor)
+{
+ return HW_CLKCTRL_HBUS & monitor;
+}
+
+unsigned imx233_get_clock_freq(enum imx233_clock_t clk)
+{
+ switch(clk)
+ {
+ case CLK_PLL: /* PLL: 480MHz when enable */
+ return imx233_is_clock_enable(CLK_PLL) ? 480000 : 0;
+ case CLK_XTAL: /* crytsal: 24MHz */
+ return 24000;
+ case CLK_CPU:
+ {
+ unsigned ref;
+ /* In bypass mode: clk_p derived from clk_xtal via int/binfrac divider
+ * otherwise, clk_p derived from clk_cpu via int div and clk_cpu
+ * derived from clk_pll fracdiv */
+ if(imx233_get_bypass_pll(CLK_CPU))
+ {
+ ref = imx233_get_clock_freq(CLK_XTAL);
+ /* Integer divide mode vs fractional divide mode */
+ if(HW_CLKCTRL_CPU & HW_CLKCTRL_CPU__DIV_XTAL_FRAC_EN)
+
+ return (ref * __XTRACT(HW_CLKCTRL_CPU, DIV_XTAL)) / 32;
+ else
+ return ref / imx233_get_clock_divisor(CLK_CPU);
+ }
+ else
+ {
+ ref = imx233_get_clock_freq(CLK_PLL);
+ /* fractional divider enable ? */
+ if(imx233_get_fractional_divisor(CLK_CPU) != 0)
+ ref = (ref * 18) / imx233_get_fractional_divisor(CLK_CPU);
+ return ref / imx233_get_clock_divisor(CLK_CPU);
+ }
+ }
+ case CLK_HBUS:
+ {
+ /* Derived from clk_p via integer/fractional div */
+ unsigned ref = imx233_get_clock_freq(CLK_CPU);
+ if(imx233_get_fractional_divisor(CLK_HBUS) != 0)
+ ref = (ref * imx233_get_fractional_divisor(CLK_HBUS)) / 32;
+ if(imx233_get_clock_divisor(CLK_HBUS) != 0)
+ ref /= imx233_get_clock_divisor(CLK_HBUS);
+ return ref;
+ }
+ case CLK_IO:
+ {
+ /* Derived from clk_pll via fracdiv */
+ unsigned ref = imx233_get_clock_freq(CLK_PLL);
+ if(imx233_get_fractional_divisor(CLK_IO) != 0)
+ ref = (ref * 18) / imx233_get_fractional_divisor(CLK_IO);
+ return ref;
+ }
+ case CLK_PIX:
+ {
+ unsigned ref;
+ /* Derived from clk_pll or clk_xtal */
+ if(!imx233_is_clock_enable(CLK_PIX))
+ ref = 0;
+ else if(imx233_get_bypass_pll(CLK_PIX))
+ ref = imx233_get_clock_freq(CLK_XTAL);
+ else
+ {
+ ref = imx233_get_clock_freq(CLK_PLL);
+ if(imx233_get_fractional_divisor(CLK_PIX) != 0)
+ ref = (ref * 18) / imx233_get_fractional_divisor(CLK_PIX);
+ }
+ return ref / imx233_get_clock_divisor(CLK_PIX);
+ }
+ case CLK_SSP:
+ {
+ unsigned ref;
+ /* Derived from clk_pll or clk_xtal */
+ if(!imx233_is_clock_enable(CLK_SSP))
+ ref = 0;
+ else if(imx233_get_bypass_pll(CLK_SSP))
+ ref = imx233_get_clock_freq(CLK_XTAL);
+ else
+ ref = imx233_get_clock_freq(CLK_IO);
+ return ref / imx233_get_clock_divisor(CLK_SSP);
+ }
+ case CLK_EMI:
+ {
+ unsigned ref;
+ /* Derived from clk_pll or clk_xtal */
+ if(imx233_get_bypass_pll(CLK_EMI))
+ {
+ ref = imx233_get_clock_freq(CLK_XTAL);
+ if(HW_CLKCTRL_EMI & HW_CLKCTRL_EMI__CLKGATE)
+ return 0;
+ else
+ return ref / __XTRACT(HW_CLKCTRL_EMI, DIV_XTAL);
+ }
+ else
+ {
+ ref = imx233_get_clock_freq(CLK_PLL);
+ if(imx233_get_fractional_divisor(CLK_EMI) != 0)
+ ref = (ref * 18) / imx233_get_fractional_divisor(CLK_EMI);
+ return ref / imx233_get_clock_divisor(CLK_EMI);
+ }
+ }
+ case CLK_XBUS:
+ return imx233_get_clock_freq(CLK_XTAL) / imx233_get_clock_divisor(CLK_XBUS);
+ default:
+ return 0;
+ }
+}