summaryrefslogtreecommitdiff
path: root/plat/sun50iw1p1/sunxi_clocks.c
diff options
context:
space:
mode:
Diffstat (limited to 'plat/sun50iw1p1/sunxi_clocks.c')
-rw-r--r--plat/sun50iw1p1/sunxi_clocks.c70
1 files changed, 53 insertions, 17 deletions
diff --git a/plat/sun50iw1p1/sunxi_clocks.c b/plat/sun50iw1p1/sunxi_clocks.c
index a071024..1f8a002 100644
--- a/plat/sun50iw1p1/sunxi_clocks.c
+++ b/plat/sun50iw1p1/sunxi_clocks.c
@@ -33,36 +33,72 @@
#include <ccmu.h>
#include "sunxi_private.h"
+#define PLL_CPUX_1008MHZ 0x1410
+#define PLL_CPUX_816MHZ 0x1010
+#define PLL_CPUX_408MHZ 0x1000
+
+
+
+static void mmio_clrsetbits32(uintptr_t addr, uint32_t mask, uint32_t bits)
+{
+ uint32_t regval = mmio_read_32(addr);
+ regval &= ~mask;
+ regval |= bits;
+ mmio_write_32(addr, regval);
+}
+
+
+static void mmio_setbits32(uintptr_t addr, uint32_t bits)
+{
+ uint32_t regval = mmio_read_32(addr);
+ regval |= bits;
+ mmio_write_32(addr, regval);
+}
+
+/* TODO (prt): we should have a timeout and return an error/success... */
+static int pll_wait_until_stable(uintptr_t addr)
+{
+ while ((mmio_read_32(addr) & PLL_STABLE_BIT) != PLL_STABLE_BIT) {
+ /* spin */
+ }
+
+ return 0;
+}
+
int sunxi_setup_clocks(uint16_t socid)
{
uint32_t reg;
+ NOTICE("BL3-1: Reprogramming clocks for a %d MHz\n");
+
/* Avoid reprogramming PERIPH0 if not necessary */
reg = mmio_read_32(CCMU_PLL_PERIPH0_CTRL_REG);
if ((reg & 0x0fffffff) != 0x41811) /* is not at 600 MHz? */
mmio_write_32(CCMU_PLL_PERIPH0_CTRL_REG, 0x80041811);
- /* Check initial CPU frequency: */
- reg = mmio_read_32(CCMU_PLL_CPUX_CTRL_REG);
+ /* Set up dividers (suitable for the target clock frequency)
+ and switch CPUX (and thus AXI & APB) to the LOSC24 clock */
+ mmio_write_32(CCMU_CPUX_AXI_CFG_REG, ( CPUX_SRCSEL_OSC24M |
+ APB_CLKDIV(4) |
+ AXI_CLKDIV(3) ));
+ udelay(20);
- if (socid == 0x1689) {
- if ((reg & 0x0fffffff) != 0x1010) { /* if not at 816 MHz: */
- /* switch CPU to 24 MHz source for changing PLL1 */
- mmio_write_32(CCMU_CPUX_AXI_CFG_REG, 0x00010000);
- udelay(1);
+ /* Set to 816MHz, but don't enable yet. */
+ mmio_write_32(CCMU_PLL_CPUX_CTRL_REG, PLL_CPUX_816MHZ);
- /* Set to 816 MHz */
- mmio_write_32(CCMU_PLL_CPUX_CTRL_REG, 0x80001010);
- udelay(1);
- }
+ /* Enable PLL_CPUX again */
+ mmio_setbits32(CCMU_PLL_CPUX_CTRL_REG, PLL_ENABLE_BIT);
+ /* Wait until the PLL_CPUX becomes stable */
+ pll_wait_until_stable(CCMU_PLL_CPUX_CTRL_REG);
- /* switch CPU to PLL1 source, AXI = CPU/3, APB = CPU/4 */
- mmio_write_32(CCMU_CPUX_AXI_CFG_REG, 0x00020302);
- udelay(1);
+ /* Wait another 20us, because Allwinner does so... */
+ udelay(20);
- } else {
- NOTICE("PLL_CPUX: %x\n", reg);
- }
+ /* Switch AXI clock back to PLL_CPUX, dividers have already been set up */
+ mmio_clrsetbits32(CCMU_CPUX_AXI_CFG_REG, CPUX_SRCSEL_MASK, CPUX_SRCSEL_PLLCPUX);
+
+ /* Wait 1000us, because Allwiner does so... */
+ udelay(1000);
/* AHB1 = PERIPH0 / (3 * 1) = 200MHz, APB1 = AHB1 / 2 */
mmio_write_32(CCMU_AHB1_APB1_CFG_REG, 0x00003180);