diff --git a/firmware/SOURCES b/firmware/SOURCES index 2510419816..887445b53c 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -526,6 +526,7 @@ target/arm/imx233/lradc-imx233.c target/arm/imx233/pwm-imx233.c target/arm/imx233/rtc-imx233.c target/arm/imx233/dcp-imx233.c +target/arm/imx233/emi-imx233.c # ifdef HAVE_TOUCHSCREEN target/arm/imx233/touchscreen-imx233.c # endif diff --git a/firmware/target/arm/imx233/clkctrl-imx233.h b/firmware/target/arm/imx233/clkctrl-imx233.h index 665674108c..30c1c54545 100644 --- a/firmware/target/arm/imx233/clkctrl-imx233.h +++ b/firmware/target/arm/imx233/clkctrl-imx233.h @@ -81,6 +81,7 @@ #define HW_CLKCTRL_EMI__DIV_XTAL_BP 8 #define HW_CLKCTRL_EMI__DIV_XTAL_BM (0xf << 8) #define HW_CLKCTRL_EMI__BUSY_REF_EMI (1 << 28) +#define HW_CLKCTRL_EMI__BUSY_REF_XTAL (1 << 29) #define HW_CLKCTRL_EMI__SYNC_MODE_EN (1 << 30) #define HW_CLKCTRL_EMI__CLKGATE (1 << 31) diff --git a/firmware/target/arm/imx233/emi-imx233.c b/firmware/target/arm/imx233/emi-imx233.c new file mode 100644 index 0000000000..b10d08134d --- /dev/null +++ b/firmware/target/arm/imx233/emi-imx233.c @@ -0,0 +1,186 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2013 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "emi-imx233.h" +#include "clkctrl-imx233.h" + +struct emi_reg_t +{ + int index; + uint32_t value; +}; + +/* hardcode all the register values for the different settings. This is ugly + * but I don't understand what they mean and it's faster this way so... + * Recall that everything should be put in iram ! + * Make sure the last value is written to register 40. */ + +/* Values extracted from Sigmatel linux port (GPL) */ + +/** mDDR value */ +static struct emi_reg_t settings_24M[15] ICONST_ATTR = +{ + {4, 0x01000101}, {7, 0x01000101}, {12, 0x02010002}, {13, 0x06060a02}, + {15, 0x01030000}, {17, 0x2d000102}, {18, 0x20200000}, {19, 0x027f1414}, + {20, 0x01021608}, {21, 0x00000002}, {26, 0x000000b3}, {32, 0x00030687}, + {33, 0x00000003}, {34, 0x000012c1}, {40, 0x00010000} +}; + +static struct emi_reg_t settings_48M[15] ICONST_ATTR = +{ + {4, 0x01000101}, {7, 0x01000101}, {13, 0x06060a02}, {12, 0x02010002}, + {15, 0x02040000}, {17, 0x2d000104}, {18, 0x1f1f0000}, {19, 0x027f0a0a}, + {20, 0x01021608}, {21, 0x00000004}, {26, 0x0000016f}, {32, 0x00060d17}, + {33, 0x00000006}, {34, 0x00002582}, {40, 0x00020000} +}; + +static struct emi_reg_t settings_60M[15] ICONST_ATTR = +{ + {4, 0x01000101}, {7, 0x01000101}, {12, 0x02020002}, {13, 0x06060a02}, + {15, 0x02040000}, {17, 0x2d000005}, {18, 0x1f1f0000}, {19, 0x027f0a0a}, + {20, 0x02040a10}, {21, 0x00000006}, {26, 0x000001cc}, {32, 0x00081060}, + {33, 0x00000008}, {34, 0x00002ee5}, {40, 0x00020000} +}; + +static struct emi_reg_t settings_80M[15] ICONST_ATTR __attribute__((alias("settings_60M"))); + +static struct emi_reg_t settings_96M[15] ICONST_ATTR = +{ + {4, 0x00000101}, {7, 0x01000001}, {12, 0x02020002}, {13, 0x06070a02}, + {15, 0x03050000}, {17, 0x2d000808}, {18, 0x1f1f0000}, {19, 0x020c1010}, + {20, 0x0305101c}, {21, 0x00000007}, {26, 0x000002e6}, {32, 0x000c1a3b}, + {33, 0x0000000c}, {34, 0x00004b0d}, {40, 0x00030000} +}; + +static struct emi_reg_t settings_120M[15] ICONST_ATTR = +{ + {4, 0x00000101}, {7, 0x01000001}, {12, 0x02020002}, {13, 0x06070a02}, + {15, 0x03050000}, {17, 0x2300080a}, {18, 0x1f1f0000}, {19, 0x020c1010}, + {20, 0x0306101c}, {21, 0x00000009}, {26, 0x000003a1}, {32, 0x000f20ca}, + {33, 0x0000000f}, {34, 0x00005dca}, {40, 0x00040000} +}; + +static struct emi_reg_t settings_133M[15] ICONST_ATTR = +{ + {4, 0x00000101}, {7, 0x01000001}, {12, 0x02020002}, {13, 0x06070a02}, + {15, 0x03050000}, {17, 0x2000080a}, {18, 0x1f1f0000}, {19, 0x020c1010}, + {20, 0x0306101c}, {21, 0x0000000a}, {26, 0x00000408}, {32, 0x0010245f}, + {33, 0x00000010}, {34, 0x00006808}, {40, 0x00040000} +}; + +static struct emi_reg_t settings_155M[15] ICONST_ATTR __attribute__((alias("settings_133M"))); + +static void set_frequency(unsigned long freq) ICODE_ATTR; + +static void set_frequency(unsigned long freq) +{ + /* Set divider and clear clkgate. Do byte access to register to avoid bothering + * with other PFDs */ + switch(freq) + { + case IMX233_EMIFREQ_151_MHz: + /* clk_emi@ref_emi/3*18/19 */ + HW_CLKCTRL_FRAC_EMI = 19; + __FIELD_SET(HW_CLKCTRL_EMI, DIV_EMI, 3); + /* ref_emi@480 MHz + * clk_emi@151.58 MHz */ + break; + case IMX233_EMIFREQ_130_MHz: + /* clk_emi@ref_emi/2*18/33 */ + HW_CLKCTRL_FRAC_EMI = 33; + __FIELD_SET(HW_CLKCTRL_EMI, DIV_EMI, 2); + /* ref_emi@480 MHz + * clk_emi@130.91 MHz */ + break; + case IMX233_EMIFREQ_64_MHz: + default: + /* clk_emi@ref_emi/5*18/27 */ + HW_CLKCTRL_FRAC_EMI = 27; + __FIELD_SET(HW_CLKCTRL_EMI, DIV_EMI, 5); + /* ref_emi@480 MHz + * clk_emi@64 MHz */ + break; + } +} + +void imx233_emi_set_frequency(unsigned long freq) ICODE_ATTR; + +void imx233_emi_set_frequency(unsigned long freq) +{ + /** FIXME we rely on the compiler to NOT use the stack here because it's + * in iram ! If it's not smart enough, one can switch the switch to use + * the irq stack since we are running interrupts disable here ! */ + /** BUG for freq<=24 MHz we must keep bypass mode since we run on xtal + * we this setting is unused by our code so ignore this bug for now */ + /** WARNING DANGER + * Changing the EMI frequency is complicated because it requires to + * completely shutdown the external memory interface. We must make sure + * that this code and all the data it uses in in iram and that no access to + * the sdram will be made during the change. Care must be taken w.r.t to + * the cache also. */ + /** FIXME assume that auto-slow is disabled here since that could put some + * clock below the minimum value and we want to spend as less time as + * possible in this state anyway. */ + + /* first disable all interrupts */ + int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS); + /* flush the cache */ + commit_discard_idcache(); + /* put DRAM into self-refresh mode */ + HW_DRAM_CTL08 |= HW_DRAM_CTL08__SREFRESH; + /* wait for DRAM to be halted */ + while(!(HW_EMI_STAT & HW_EMI_STAT__DRAM_HALTED)); + /* load timings */ + struct emi_reg_t *regs; + if(freq <= 24000) regs = settings_24M; + else if(freq <= 48000) regs = settings_48M; + else if(freq <= 60000) regs = settings_60M; + else if(freq <= 80000) regs = settings_80M; + else if(freq <= 96000) regs = settings_96M; + else if(freq <= 120000) regs = settings_120M; + else if(freq <= 133000) regs = settings_133M; + else regs = settings_155M; + + do + HW_DRAM_CTLxx(regs->index) = regs->value; + while((regs++)->index != 40); + /* switch emi to xtal */ + __REG_SET(HW_CLKCTRL_CLKSEQ) = HW_CLKCTRL_CLKSEQ__BYPASS_EMI; + /* wait for transition */ + while(HW_CLKCTRL_EMI & HW_CLKCTRL_EMI__BUSY_REF_XTAL); + /* put emi dll into reset mode */ + __REG_SET(HW_EMI_CTRL) = HW_EMI_CTRL__DLL_RESET | HW_EMI_CTRL__DLL_SHIFT_RESET; + /* load the new frequency dividers */ + set_frequency(freq); + /* switch emi back to pll */ + __REG_CLR(HW_CLKCTRL_CLKSEQ) = HW_CLKCTRL_CLKSEQ__BYPASS_EMI; + /* wait for transition */ + while(HW_CLKCTRL_EMI & HW_CLKCTRL_EMI__BUSY_REF_EMI); + /* allow emi dll to lock again */ + __REG_CLR(HW_EMI_CTRL) = HW_EMI_CTRL__DLL_RESET | HW_EMI_CTRL__DLL_SHIFT_RESET; + /* wait for lock */ + while(!(HW_DRAM_CTL04 & HW_DRAM_CTL04__DLLLOCKREG)); + /* get DRAM out of self-refresh mode */ + HW_DRAM_CTL08 &= ~HW_DRAM_CTL08__SREFRESH; + /* wait for DRAM to be to run again */ + while(HW_EMI_STAT & HW_EMI_STAT__DRAM_HALTED); + + restore_interrupt(oldstatus); +} diff --git a/firmware/target/arm/imx233/emi-imx233.h b/firmware/target/arm/imx233/emi-imx233.h new file mode 100644 index 0000000000..8106d27dfe --- /dev/null +++ b/firmware/target/arm/imx233/emi-imx233.h @@ -0,0 +1,260 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2013 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __EMI_IMX233_H__ +#define __EMI_IMX233_H__ + +#include "cpu.h" +#include "system.h" +#include "system-target.h" + +#define HW_EMI_BASE 0x80020000 + +#define HW_EMI_CTRL (*(volatile uint32_t *)(HW_EMI_BASE + 0x0)) +#define HW_EMI_CTRL__DLL_SHIFT_RESET (1 << 25) +#define HW_EMI_CTRL__DLL_RESET (1 << 24) + +/* this register is undocumented but exists, I put the whole doc here */ +#define HW_EMI_STAT (*(volatile uint32_t *)(HW_EMI_BASE + 0x10)) +#define HW_EMI_STAT__DRAM_PRESENT (1 << 31) +#define HW_EMI_STAT__NOR_PRESENT (1 << 30) +#define HW_EMI_STAT__LARGE_DRAM_ENABLED (1 << 29) +#define HW_EMI_STAT__DRAM_HALTED (1 << 1) +#define HW_EMI_STAT__NOR_BUSY (1 << 0) + +/* another undocumented registers (there are some more) */ +#define HW_EMI_TIME (*(volatile uint32_t *)(HW_EMI_BASE + 0x20)) +#define HW_EMI_TIME__THZ_BP 24 +#define HW_EMI_TIME__THZ_BM (0xf << 24) +#define HW_EMI_TIME__TDH_BP 16 +#define HW_EMI_TIME__TDH_BM (0xf << 16) +#define HW_EMI_TIME__TDS_BP 8 +#define HW_EMI_TIME__TDS_BM (0x1f << 8) +#define HW_EMI_TIME__TAS_BP 0 +#define HW_EMI_TIME__TAS_BM (0xf << 0) + +/** WARNING: the HW_DRAM_* registers don't have a SCT variant ! */ +#define HW_DRAM_BASE 0x800E0000 + +#define HW_DRAM_CTLxx(xx) (*(volatile uint32_t *)(HW_DRAM_BASE + 0x4 * (xx))) + +#define HW_DRAM_CTL00 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x0)) +#define HW_DRAM_CTL01 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x4)) +#define HW_DRAM_CTL02 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x8)) +#define HW_DRAM_CTL03 (*(volatile uint32_t *)(HW_DRAM_BASE + 0xc)) + +#define HW_DRAM_CTL04 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x10)) +#define HW_DRAM_CTL04__DLL_BYPASS_MODE (1 << 24) +#define HW_DRAM_CTL04__DLLLOCKREG (1 << 16) + +#define HW_DRAM_CTL05 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x14)) +#define HW_DRAM_CTL05__EN_LOWPOWER_MODE (1 << 0) + +#define HW_DRAM_CTL06 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x18)) +#define HW_DRAM_CTL07 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x1c)) + +#define HW_DRAM_CTL08 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x20)) +#define HW_DRAM_CTL08__SREFRESH (1 << 8) + +#define HW_DRAM_CTL09 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x24)) + +#define HW_DRAM_CTL10 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x28)) +#define HW_DRAM_CTL10__TEMRS_BP 8 +#define HW_DRAM_CTL10__TEMRS_BM (0x3 << 8) + +#define HW_DRAM_CTL11 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x2c)) +#define HW_DRAM_CTL11__CASLAT_BP 0 +#define HW_DRAM_CTL11__CASLAT_BM (0x7 << 0) + +#define HW_DRAM_CTL12 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x30)) +#define HW_DRAM_CTL12__TCKE_BP 0 +#define HW_DRAM_CTL12__TCKE_BM (0x7 << 0) +#define HW_DRAM_CTL12__TRRD_BP 16 +#define HW_DRAM_CTL12__TRRD_BM (0x7 << 16) +#define HW_DRAM_CTL12__TWR_INT_BP 24 +#define HW_DRAM_CTL12__TWR_INT_BM (0x7 << 24) + +#define HW_DRAM_CTL13 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x34)) +#define HW_DRAM_CTL13__TWTR_BP 0 +#define HW_DRAM_CTL13__TWTR_BM (0x7 << 0) +#define HW_DRAM_CTL13__CASLAT_LIN_BP 16 +#define HW_DRAM_CTL13__CASLAT_LIN_BM (0xf << 16) +#define HW_DRAM_CTL13__CASLAT_LIN_GATE_BP 24 +#define HW_DRAM_CTL13__CASLAT_LIN_GATE_BM (0xf << 24) + +#define HW_DRAM_CTL14 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x38)) + +#define HW_DRAM_CTL15 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x3c)) +#define HW_DRAM_CTL15__TDAL_BP 16 +#define HW_DRAM_CTL15__TDAL_BM (0xf << 16) +#define HW_DRAM_CTL15__TRP_BP 24 +#define HW_DRAM_CTL15__TRP_BM (0xf << 24) + +#define HW_DRAM_CTL16 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x40)) +#define HW_DRAM_CTL16__TMRD_BP 24 +#define HW_DRAM_CTL16__TMRD_BM (0x1f << 24) + +#define HW_DRAM_CTL17 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x44)) +#define HW_DRAM_CTL17__TRC_BP 0 +#define HW_DRAM_CTL17__TRC_BM (0x1f << 0) +#define HW_DRAM_CTL17__DLL_INCREMENT_BP 8 +#define HW_DRAM_CTL17__DLL_INCREMENT_BM (0xff << 0) +#define HW_DRAM_CTL17__DLL_START_POINT_BP 24 +#define HW_DRAM_CTL17__DLL_START_POINT_BM (0xff << 24) + +#define HW_DRAM_CTL18 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x48)) +#define HW_DRAM_CTL17__DLL_DQS_DELAY_0_BP 16 +#define HW_DRAM_CTL17__DLL_DQS_DELAY_0_BM (0x7f << 16) +#define HW_DRAM_CTL17__DLL_DQS_DELAY_1_BP 24 +#define HW_DRAM_CTL17__DLL_DQS_DELAY_1_BM (0x7f << 24) + +#define HW_DRAM_CTL19 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x4c)) +#define HW_DRAM_CTL19__DQS_OUT_SHIFT_BP 16 +#define HW_DRAM_CTL19__DQS_OUT_SHIFT_BM (0x7f << 16) + +#define HW_DRAM_CTL20 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x50)) +#define HW_DRAM_CTL20__WR_DQS_SHIFT_BP 0 +#define HW_DRAM_CTL20__WR_DQS_SHIFT_BM (0x7f << 0) +#define HW_DRAM_CTL20__TRAS_MIN_BP 16 +#define HW_DRAM_CTL20__TRAS_MIN_BM (0xff << 16) +#define HW_DRAM_CTL20__TRCD_INT_BP 24 +#define HW_DRAM_CTL20__TRCD_INT_BM (0xff << 24) + +#define HW_DRAM_CTL21 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x54)) +#define HW_DRAM_CTL21__TRFC_BP 0 +#define HW_DRAM_CTL21__TRFC_BM (0xff << 0) + +#define HW_DRAM_CTL22 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x58)) +#define HW_DRAM_CTL23 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x5c)) +#define HW_DRAM_CTL24 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x60)) +#define HW_DRAM_CTL25 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x64)) + +#define HW_DRAM_CTL26 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x68)) +#define HW_DRAM_CTL26__TREF_BP 0 +#define HW_DRAM_CTL26__TREF_BM (0xfff << 0) + +#define HW_DRAM_CTL27 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x6c)) +#define HW_DRAM_CTL28 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x70)) +#define HW_DRAM_CTL29 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x74)) +#define HW_DRAM_CTL30 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x78)) + +#define HW_DRAM_CTL31 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x7c)) +#define HW_DRAM_CTL31__TDLL_BP 16 +#define HW_DRAM_CTL31__TDLL_BM (0xffff << 16) + +#define HW_DRAM_CTL32 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x80)) +#define HW_DRAM_CTL32__TRAS_MAX_BP 0 +#define HW_DRAM_CTL32__TRAS_MAX_BM (0xffff << 0) +#define HW_DRAM_CTL32__TXSNR_BP 16 +#define HW_DRAM_CTL32__TXSNR_BM (0xffff << 16) + +#define HW_DRAM_CTL33 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x84)) +#define HW_DRAM_CTL33__TXSR_BP 0 +#define HW_DRAM_CTL33__TXSR_BM (0xffff << 0) + +#define HW_DRAM_CTL34 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x88)) +#define HW_DRAM_CTL34__TINIT_BP 0 +#define HW_DRAM_CTL34__TINIT_BM 0xffffff + +#define HW_DRAM_CTL35 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x8c)) +#define HW_DRAM_CTL36 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x90)) +#define HW_DRAM_CTL37 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x94)) +#define HW_DRAM_CTL38 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x98)) +#define HW_DRAM_CTL39 (*(volatile uint32_t *)(HW_DRAM_BASE + 0x9a)) + +#define HW_DRAM_CTL40 (*(volatile uint32_t *)(HW_DRAM_BASE + 0xa0)) +#define HW_DRAM_CTL40__TPDEX_BP 16 +#define HW_DRAM_CTL40__TPDEX_BM (0xffff << 16) + +/** Interesting fields: + * - TCKE: CTL12 + * - TDAL: CTL15 + * - TDLL: CTL31 + * - TEMRS: CTL10 + * - TINIT: CTL34 + * - TMRD: CTL16 + * - TPDEX: CTL40 + * - TRAS_MAX: CTL32 + * - TRAS_MIN: CTL20 + * - TRC: CTL17 + * - TRCD_INT: CTL20 + * - TREF: CTL26 + * - TRFC: CTL21 + * - TRP: CTL15 + * - TRRD: CTL12 + * - TWR_INT: CTL12 + * - TWTR: CTL13 + * - TXSNR: CTL32 + * - TXSR: CTL33 + * - DLL_DQS_DELAY_BYPASS_0 + * - DLL_DQS_DELAY_BYPASS_1 + * - DQS_OUT_SHIFT_BYPASS + * - WR_DQS_SHIFT_BYPASS + * - DLL_INCREMENT: CTL17 + * - DLL_START_POINT: CTL17 + * - DLL_DQS_DELAY_0: CTL18 + * - DLL_DQS_DELAY_1: CTL18 + * - DQS_OUT_SHIFT: CTL19 + * - WR_DQS_SHIFT: CTL20 + * - CAS: CTL11 + * - DLL_BYPASS_MODE: CTL04 + * - SREFRESH: CTL08 + * - CASLAT_LIN: CTL13 + * - CASLAT_LIN_GATE: CTL13 + * + * Interesting registers: + * - CTL04: DLL_BYPASS_MODE + * - CTL08: SREFRESH + * - CTL10: TEMRS + * - CTL11: CASLAT + * - CTL12: TCKE TRRD TWR_INT + * - CTL13: TWTR CASLAT_LIN CASLAT_LIN_GATE + * - CTL15: TDAL TRP + * - CTL16: TMRD + * - CTL17: TRC DLL_INCREMENT DLL_START_POINT + * - CTL18: DLL_DQS_DELAY_0 DLL_DQS_DELAY_1 + * - CTL19: DQS_OUT_SHIFT + * - CTL20: WR_DQS_SHIFT TRAS_MIN TRCD_INT + * - CTL21 TRFC + * - CTL26: TREF + * - CTL31: TDLL + * - CTL32: TRAS_MAX TXSNR TXSR: CTL33 + * - CTL34: TINIT + * - CTL40: TPDEX + + * - DLL_DQS_DELAY_BYPASS_0 + * - DLL_DQS_DELAY_BYPASS_1 + * - DQS_OUT_SHIFT_BYPASS + * - WR_DQS_SHIFT_BYPASS + */ + +/** + * Absolute maximum EMI speed: 151.58 MHz (mDDR), 130.91 MHz (DDR) + * Intermediate EMI speeds: 130.91 MHz, 120.00 MHz, 64 MHz, 24 MHz + * Absolute minimum CPU speed: 24 MHz */ +#define IMX233_EMIFREQ_151_MHz 151580 +#define IMX233_EMIFREQ_130_MHz 130910 +#define IMX233_EMIFREQ_120_MHz 120000 +#define IMX233_EMIFREQ_64_MHz 64000 +#define IMX233_EMIFREQ_24_MHz 24000 + +void imx233_emi_set_frequency(unsigned long freq); + +#endif /* __EMI_IMX233_H__ */ diff --git a/firmware/target/arm/imx233/system-imx233.c b/firmware/target/arm/imx233/system-imx233.c index 07ab62d680..68f063512d 100644 --- a/firmware/target/arm/imx233/system-imx233.c +++ b/firmware/target/arm/imx233/system-imx233.c @@ -36,6 +36,7 @@ #include "lradc-imx233.h" #include "rtc-imx233.h" #include "power-imx233.h" +#include "emi-imx233.h" #include "lcd.h" #include "backlight-target.h" #include "button.h" @@ -196,6 +197,8 @@ void set_cpu_frequency(long frequency) imx233_clkctrl_set_fractional_divisor(CLK_CPU, 19); imx233_clkctrl_set_clock_divisor(CLK_CPU, 1); imx233_clkctrl_set_bypass_pll(CLK_CPU, false); + + imx233_emi_set_frequency(IMX233_EMIFREQ_130_MHz); /* ref_cpu@480 MHz * ref_emi@480 MHz * clk_emi@130.91 MHz @@ -211,12 +214,30 @@ void set_cpu_frequency(long frequency) imx233_clkctrl_set_fractional_divisor(CLK_CPU, 33); imx233_clkctrl_set_clock_divisor(CLK_CPU, 1); imx233_clkctrl_set_bypass_pll(CLK_CPU, false); + + imx233_emi_set_frequency(IMX233_EMIFREQ_130_MHz); /* ref_cpu@480 MHz * ref_emi@480 MHz * clk_emi@130.91 MHz * clk_p@261.82 MHz * clk_h@130.91 MHz */ break; + case IMX233_CPUFREQ_64_MHz: + /* set VDDD to 1.050 mV (brownout at 0.975 mV) */ + imx233_power_set_regulator(REGULATOR_VDDD, 1050, 975); + /* clk_h@clk_p */ + imx233_clkctrl_set_clock_divisor(CLK_HBUS, 1); + /* clk_p@ref_cpu/5*18/27 */ + imx233_clkctrl_set_fractional_divisor(CLK_CPU, 27); + imx233_clkctrl_set_clock_divisor(CLK_CPU, 5); + imx233_clkctrl_set_bypass_pll(CLK_CPU, false); + + imx233_emi_set_frequency(IMX233_EMIFREQ_64_MHz); + /* ref_cpu@480 MHz + * ref_emi@480 MHz + * clk_emi@64 MHz + * clk_p@64 MHz + * clk_h@64 MHz */ default: break; } diff --git a/firmware/target/arm/imx233/system-target.h b/firmware/target/arm/imx233/system-target.h index 5515597570..c6073a9ae3 100644 --- a/firmware/target/arm/imx233/system-target.h +++ b/firmware/target/arm/imx233/system-target.h @@ -37,6 +37,18 @@ #define HW_DIGCTL_MICROSECONDS (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0xC0)) +#define HW_DIGCTL_ARMCACHE (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0x2b0)) +#define HW_DIGCTL_ARMCACHE__ITAG_SS_BP 0 +#define HW_DIGCTL_ARMCACHE__ITAG_SS_BM (3 << 0) +#define HW_DIGCTL_ARMCACHE__DTAG_SS_BP 4 +#define HW_DIGCTL_ARMCACHE__DTAG_SS_BM (3 << 4) +#define HW_DIGCTL_ARMCACHE__CACHE_SS_BP 8 +#define HW_DIGCTL_ARMCACHE__CACHE_SS_BM (3 << 8) +#define HW_DIGCTL_ARMCACHE__DRTY_SS_BP 12 +#define HW_DIGCTL_ARMCACHE__DRTY_SS_BM (3 << 12) +#define HW_DIGCTL_ARMCACHE__VALID_SS_BP 16 +#define HW_DIGCTL_ARMCACHE__VALID_SS_BM (3 << 16) + /* USB Phy */ #define HW_USBPHY_BASE 0x8007C000 #define HW_USBPHY_PWD (*(volatile uint32_t *)(HW_USBPHY_BASE + 0)) @@ -48,17 +60,17 @@ * Absolute maximum CPU speed: 454.74 MHz * Intermediate CPU speeds: 392.73 MHz, 360MHz, 261.82 MHz, 64 MHz * Absolute minimum CPU speed: 24 MHz */ -#define IMX233_CPUFREQ_454_MHz 454740000 -#define IMX233_CPUFREQ_392_MHz 392730000 -#define IMX233_CPUFREQ_360_MHz 360000000 -#define IMX233_CPUFREQ_261_MHz 261820000 -#define IMX233_CPUFREQ_64_MHz 64000000 -#define IMX233_CPUFREQ_24_MHz 24000000 +#define IMX233_CPUFREQ_454_MHz 454740 +#define IMX233_CPUFREQ_392_MHz 392730 +#define IMX233_CPUFREQ_360_MHz 360000 +#define IMX233_CPUFREQ_261_MHz 261820 +#define IMX233_CPUFREQ_64_MHz 64000 +#define IMX233_CPUFREQ_24_MHz 24000 -#define CPUFREQ_DEFAULT IMX233_CPUFREQ_261_MHz -#define CPUFREQ_NORMAL IMX233_CPUFREQ_261_MHz +#define CPUFREQ_DEFAULT IMX233_CPUFREQ_64_MHz +#define CPUFREQ_NORMAL IMX233_CPUFREQ_64_MHz #define CPUFREQ_MAX IMX233_CPUFREQ_454_MHz -#define CPUFREQ_SLEEP IMX233_CPUFREQ_261_MHz +#define CPUFREQ_SLEEP IMX233_CPUFREQ_64_MHz void udelay(unsigned us); bool imx233_us_elapsed(uint32_t ref, unsigned us_delay);