#include "pll.h" /********MCOM-02 REGMAP DEFINE*******************************************/ /***************************System Registers*****************************/ #define CMCTR_BASE 0x38094000 #define GATE_SYS_CTR (*(volatile unsigned int*)(CMCTR_BASE + 0x04c)) #define CLK_I2C2_EN (1 << 18) #define CLK_I2C1_EN (1 << 17) #define CLK_I2C0_EN (1 << 16) #define GATE_DSP_CTR (*(volatile unsigned int*)(CMCTR_BASE + 0x068)) #define DSPENC_EN (1 << 3) #define DSPEXT_EN (1 << 2) #define DSP1_EN (1 << 1) #define DSP0_EN (1 << 0) #define SEL_APLL (*(volatile unsigned int*)(CMCTR_BASE + 0x100)) #define SEL_CPLL (*(volatile unsigned int*)(CMCTR_BASE + 0x104)) #define SEL_DPLL (*(volatile unsigned int*)(CMCTR_BASE + 0x108)) #define SEL_SPLL (*(volatile unsigned int*)(CMCTR_BASE + 0x10c)) #define SEL_VPLL (*(volatile unsigned int*)(CMCTR_BASE + 0x110)) #define PLL_LOCK_BIT (1 << 31) /***************************GPIO******************************************/ #define GPIO0_BASE 0x38034000 #define GPIO0(a) (*(volatile unsigned int*)(GPIO0_BASE + (a))) #define SWPORTA_DR 0x00 #define SWPORTA_DDR 0x04 #define SWPORTA_CTL 0x08 #define SWPORTB_DR 0x0c #define SWPORTB_DDR 0x10 #define SWPORTB_CTL 0x14 #define SWPORTC_DR 0x18 #define SWPORTC_DDR 0x1c #define SWPORTC_CTL 0x20 #define SWPORTD_DR 0x24 #define SWPORTD_DDR 0x28 #define SWPORTD_CTL 0x2c #define GPIOA29_I2C0_SDA (1 << 29) #define GPIOA29_I2C0_SCL (1 << 30) #define GPIOD22_I2C1_SDA (1 << 22) #define GPIOD23_I2C1_SCL (1 << 23) #define GPIOD24_I2C2_SDA (1 << 24) #define GPIOD25_I2C2_SCL (1 << 25) /***FAN53555**************************************************************/ /***5 A, 2.4MHz, Digitally Programmable TinyBuck Regulator****************/ #define FAN53555_I2C_NUM 0 #define FAN53555_I2C_SLAVE_ADDR 0x60 #define FAN53555_VSEL0_REG 0 #define FAN53555_OPTION4_VOLT_TO_SEL(mv) (((mv) - 603)/12.826f + 1) /***CPU FREQ TABLE********************************************************/ #define CPU_FREQ_VOLTAGE_SIZE 3 const unsigned int CPU_FREQ_VOLTAGE[CPU_FREQ_VOLTAGE_SIZE][2] __attribute__ ((aligned(8))) = { // MHz, mV {816, 1040}, {912, 1103}, {1008, 1205} }; /***DSP FREQ TABLE********************************************************/ #define DSP_FREQ_VOLTAGE_SIZE 3 const unsigned int DSP_FREQ_VOLTAGE[CPU_FREQ_VOLTAGE_SIZE][2] __attribute__ ((aligned(8))) = { // MHz, mV {696, 1040}, {768, 1103}, {888, 1205} }; /*I2C Settings*/ #define BASE_I2C0 0x3802c000 #define BASE_I2C1 0x3802d000 #define BASE_I2C2 0x3802e000 #define I2C_CMD_READ (1 << 8) #define I2C_CMD_WRITE (0 << 8) #define I2C_STATUS_TFE (1 << 2) #define I2C_STATUS_RFNE (1 << 3) const unsigned int I2C_GPIO[3][3] __attribute__ ((aligned(8))) = { { SWPORTA_CTL, GPIOA29_I2C0_SDA, GPIOA29_I2C0_SCL}, { SWPORTD_CTL, GPIOD22_I2C1_SDA, GPIOD23_I2C1_SCL}, { SWPORTD_CTL, GPIOD24_I2C2_SDA, GPIOD25_I2C2_SCL}, }; typedef struct { volatile unsigned int IC_CON; volatile unsigned int IC_TAR; volatile unsigned int IC_SAR; volatile unsigned int IC_HS_MADDR; volatile unsigned int IC_DATA_CMD; volatile unsigned int IC_SS_SCL_HCNT; volatile unsigned int IC_SS_SCL_LCNT; volatile unsigned int IC_FS_SCL_HCNT; volatile unsigned int IC_FS_SCL_LCNT; volatile unsigned int IC_HS_SCL_HCNT; volatile unsigned int IC_HS_SCL_LCNT; volatile unsigned int IC_INTR_STAT; volatile unsigned int IC_INTR_MASK; volatile unsigned int IC_RAW_INTR_STAT; volatile unsigned int IC_RX_TL; volatile unsigned int IC_TX_TL; volatile unsigned int IC_CLR_INTR; volatile unsigned int IC_CLR_RX_UNDER; volatile unsigned int IC_CLR_RX_OVER; volatile unsigned int IC_CLR_TX_OVER; volatile unsigned int IC_CLR_RD_REQ; volatile unsigned int IC_CLR_TX_ABRT; volatile unsigned int IC_CLR_RX_DONE; volatile unsigned int IC_CLR_ACTIVITY; volatile unsigned int IC_CLR_STOP_DET; volatile unsigned int IC_CLR_START_DET; volatile unsigned int IC_CLR_GEN_CALL; volatile unsigned int IC_ENABLE; volatile unsigned int IC_STATUS; volatile unsigned int IC_TXFLR; volatile unsigned int IC_RXFLR; volatile unsigned int IC_SDA_HOLD; volatile unsigned int IC_TX_ABRT_SOURCE; volatile unsigned int IC_SLV_DATA_NACK_ONLY; volatile unsigned int IC_DMA_CR; volatile unsigned int IC_DMA_TDLR; volatile unsigned int IC_DMA_RDLR; volatile unsigned int IC_SDA_SETUP; volatile unsigned int IC_ACK_GENERAL_CALL; volatile unsigned int IC_ENABLE_STATUS; volatile unsigned int IC_FS_SPKLEN; volatile unsigned int IC_HS_SPKLEN; volatile unsigned char RESERVED0[76]; volatile unsigned int IC_COMP_PARAM_1; volatile unsigned int IC_COMP_VERSION; volatile unsigned int IC_COMP_TYPE; } i2c_reg_t; typedef union { struct { volatile unsigned int NSEL0 : 6; volatile unsigned int MODE0 : 1; volatile unsigned int BUCK_EN0 : 1; volatile unsigned int reserved : 24; }; volatile unsigned int regval; }vsel0_reg_t; enum dw_i2c_speed_mode { I2C_SPEED_STANDART = 0x1, // standard speed (100 kbps) I2C_SPEED_FAST = 0x2, // fast speed (400 kbps) I2C_SPEED_HIGH = 0x3 // high speed (3400 kbps) }; enum dw_i2c_address_mode { I2C_7BIT_ADDRESS = 0x0, // 7-bit address mode. Only the 7 LSBs // of the slave and/or target address // are relevant. I2C_10BIT_ADDRESS = 0x1 // 10-bit address mode. The 10 LSBs of // the slave and/or target address are // relevant. }; enum dw_i2c_tx_mode { I2C_TX_TARGET = 0x0, // normal transfer using target address I2C_TX_GEN_CALL = 0x1, // issue a general call I2C_TX_START_BYTE = 0x3 // issue a start byte I2C command }; void setCPUPLLFreq(unsigned int MHz); void setDSPPLLFreq(unsigned int MHz); int setCoreVoltage(unsigned int voltage); i2c_reg_t* getI2CHandler(unsigned int i2cNum) { i2cNum &= 0x3; return (i2c_reg_t*) (BASE_I2C0 + 0x1000 * i2cNum); } void initI2CTx(unsigned int i2cNum, unsigned int slave) { volatile unsigned int temp; i2c_reg_t* i2c; i2cNum &= 0x3; //Enable clock GATE_SYS_CTR |= CLK_I2C0_EN << i2cNum; //Enable GPIO GPIO0(I2C_GPIO[i2cNum][0]) |= I2C_GPIO[i2cNum][1] | I2C_GPIO[i2cNum][2]; i2c = getI2CHandler(i2cNum); i2c->IC_ENABLE = 0; //Disable i2c; i2c->IC_INTR_MASK = 0; //Mask interrupts temp = i2c->IC_CLR_INTR; //Clear interrupts (void) temp; i2c->IC_CON = 1 //Enable master mode | (I2C_SPEED_STANDART << 1) //Setup speed | (I2C_7BIT_ADDRESS << 3) //Set address bit-mode slave | (1 << 5) //Restart enable | (1 << 6); //Disable slave mode i2c->IC_TAR = (slave & 0x3FF) //Set slave address | (I2C_TX_TARGET << 10) //Set TX mode | (I2C_7BIT_ADDRESS << 12); //Set address bit-mode master //i2c->IC_INTR_MASK = 0xFFF; //Unmask interrupts i2c->IC_ENABLE = 1; //Enable i2c; } unsigned int readI2CReg(unsigned int i2cNum, unsigned int regNum) { i2cNum &= 0x3; regNum &= 0xFF; i2c_reg_t* i2c = getI2CHandler(i2cNum); //Send register number i2c->IC_DATA_CMD = regNum | I2C_CMD_WRITE; //Wait sending while(!(i2c->IC_STATUS & I2C_STATUS_TFE)); //Read answer i2c->IC_DATA_CMD = I2C_CMD_READ; //Wait data while(!(i2c->IC_STATUS & I2C_STATUS_RFNE)); return (i2c->IC_DATA_CMD & 0xFF); } void writeI2CReg(unsigned int i2cNum, unsigned int regNum, unsigned int regVal) { i2cNum &= 0x3; regNum &= 0xFF; regVal &= 0xFF; i2c_reg_t* i2c = getI2CHandler(i2cNum); //Send register number i2c->IC_DATA_CMD = regNum | I2C_CMD_WRITE; //Send register value i2c->IC_DATA_CMD = regVal | I2C_CMD_WRITE; //Wait sending while(!(i2c->IC_STATUS & I2C_STATUS_TFE)); } void i2c_delay() { volatile int i; for(i = 0; i < 10000; i++) { asm volatile("nop"); } } int setCPUFreq(unsigned int MHz) { unsigned int dsp_voltage, last_freq, voltage; if(MHz < MIN_CPU_FREQ_MHZ || MHz > MAX_CPU_FREQ_MHZ || (voltage = getCPUVoltage(MHz)) == 0) { return 1; } //Check DSP freq and voltage dsp_voltage = getDSPVoltage(getCurrentDSPFreq()); if(dsp_voltage > voltage) voltage = dsp_voltage; //Set max voltage //Save current CPU freq last_freq = getCurrentCPUFreq(); //Set default CPU freq setCPUPLLFreq(DEFAULT_XTI_CLOCK); //Set Core Voltage if(setCoreVoltage(voltage)) { //Restore CPU freq setCPUPLLFreq(last_freq); return 2; }; //Set CPU freq setCPUPLLFreq(MHz); return 0; } int setDSPFreq(unsigned int MHz) { unsigned int cpu_voltage, last_freq, voltage; if(MHz < MIN_DSP_FREQ_MHZ || MHz > MAX_DSP_FREQ_MHZ || (voltage = getDSPVoltage(MHz)) == 0) { return 1; } //Enable DSP_CLK GATE_DSP_CTR |= DSP0_EN | DSP1_EN | DSPEXT_EN | DSPENC_EN ; //Check CPU freq and voltage cpu_voltage = getCPUVoltage(getCurrentCPUFreq()); if(cpu_voltage > voltage) voltage = cpu_voltage; //Set max voltage //Save current DSP freq last_freq = getCurrentDSPFreq(); //Set default DSP freq setDSPPLLFreq(DEFAULT_XTI_CLOCK); //Set Core Voltage if(setCoreVoltage(voltage)) { //Restore DSP freq setDSPPLLFreq(last_freq); return 2; }; //Set DSP freq setDSPPLLFreq(MHz); return 0; } int setCoreVoltage(unsigned int voltage) { vsel0_reg_t sel0_reg; sel0_reg.regval = 0; sel0_reg.NSEL0 = FAN53555_OPTION4_VOLT_TO_SEL(voltage); //Set voltage sel0_reg.MODE0 = 0; //Allow Auto-PFM mode sel0_reg.BUCK_EN0 = 1; //Software buck enable initI2CTx(FAN53555_I2C_NUM, FAN53555_I2C_SLAVE_ADDR); writeI2CReg(FAN53555_I2C_NUM, FAN53555_VSEL0_REG, sel0_reg.regval); i2c_delay(); if(readI2CReg(FAN53555_I2C_NUM, FAN53555_VSEL0_REG) != sel0_reg.regval) { return 1; } return 0; } unsigned int getCPUVoltage(unsigned int MHz) { int i; for(i = 0; i < CPU_FREQ_VOLTAGE_SIZE; i++) { if(MHz <= CPU_FREQ_VOLTAGE[i][0]) { return CPU_FREQ_VOLTAGE[i][1]; } } return 0; } unsigned int getDSPVoltage(unsigned int MHz) { int i; for(i = 0; i < DSP_FREQ_VOLTAGE_SIZE; i++) { if(MHz <= DSP_FREQ_VOLTAGE[i][0]) { return DSP_FREQ_VOLTAGE[i][1]; } } return 0; } unsigned int getCurrentCPUFreq() { int sel = (SEL_APLL & 0xFF); if(sel > 0x3D) sel = 0x3D; return (sel + 1) * DEFAULT_XTI_CLOCK; } unsigned int getCurrentDSPFreq() { int sel = (SEL_DPLL & 0xFF); if(sel > 0x3D) sel = 0x3D; return (sel + 1) * DEFAULT_XTI_CLOCK; } void setCPUPLLFreq(unsigned int MHz) { int sel = (MHz / DEFAULT_XTI_CLOCK) - 1; if(sel < 0) sel = 0; SEL_APLL = sel; while(!(SEL_APLL & PLL_LOCK_BIT)); } void setDSPPLLFreq(unsigned int MHz) { int sel = (MHz / DEFAULT_XTI_CLOCK) - 1; if(sel < 0) sel = 0; SEL_DPLL = sel; while(!(SEL_DPLL & PLL_LOCK_BIT)); }