/* * Carsten Langgaard, carstenl@mips.com * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved. * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * * AR7 specific setup. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_AVM_POWERMETER #include #endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ /*--- #define AR7_CLK_DEBUG ---*/ #if defined(AR7_CLK_DEBUG) #define DBG_TRC printk #else/*--- #if defined(AR7_CLK_DEBUG) ---*/ #define DBG_TRC(a,...) #endif/*--- #else ---*//*--- #if defined(AR7_CLK_DEBUG) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static spinlock_t ar7_clock_spinlock; static unsigned int ar7_current_system_clock; #define default_ar7_lan_xtal 25000000 const unsigned int ar7_lan_xtal = default_ar7_lan_xtal; #define default_ar7_dsp_xtal 35328000 const unsigned int ar7_dsp_xtal = default_ar7_dsp_xtal; #if defined(CONFIG_AR7_CLOCK_SWITCH) struct _ar7_clk_notify_system_clock_change { struct _ar7_clk_notify_system_clock_change *next; enum _avm_clock_id clock_id; unsigned int (*notify)(enum _avm_clock_id, unsigned int); }; static spinlock_t ar7_clock_switch_spinlock; static struct _ar7_clk_notify_system_clock_change *ar7_system_clock_notify_first; static struct proc_dir_entry *ar7_change_clock_entry; #define MAX_CLK_LISTENTRY 10 static struct _clk_listentry { volatile unsigned int locked; struct _ar7_clk_notify_system_clock_change entry; } clk_listentry[MAX_CLK_LISTENTRY]; /*--------------------------------------------------------------------------------*\ * kmalloc darf hier nicht verwendet werden (zu frueh!) \*--------------------------------------------------------------------------------*/ static struct _ar7_clk_notify_system_clock_change *alloc_clk_listentry(void) { unsigned int i; long flags; spin_lock_irqsave(&ar7_clock_spinlock, flags); for(i = 0; i < MAX_CLK_LISTENTRY; i++) { if(clk_listentry[i].locked == 0) { clk_listentry[i].locked = 1; spin_unlock_irqrestore(&ar7_clock_spinlock, flags); /*--- printk("[clk]alloc_clk_listentry: %d\n", i); ---*/ return &clk_listentry[i].entry; } } spin_unlock_irqrestore(&ar7_clock_spinlock, flags); printk("[clk]alloc_clk_listentry: failed!\n"); return NULL; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void free_clk_listentry(struct _ar7_clk_notify_system_clock_change *entry) { unsigned int i; long flags; spin_lock_irqsave(&ar7_clock_spinlock, flags); for(i = 0; i < MAX_CLK_LISTENTRY; i++) { if(clk_listentry[i].locked && (&clk_listentry[i].entry == entry)) { clk_listentry[i].locked = 0; /*--- printk("[clk]free_clk_listentry: %d\n", i); ---*/ spin_unlock_irqrestore(&ar7_clock_spinlock, flags); return; } } spin_unlock_irqrestore(&ar7_clock_spinlock, flags); printk("[clk]free_clk_listentry: failed!\n"); return; } #endif /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int __init ar7_clk_switch_init(void); static unsigned int ar7_call_clock_notifier(enum _avm_clock_id clock_id, unsigned int clk); static unsigned int ar7_set_mips_clock(unsigned int clk); static unsigned int ar7_set_system_clock(unsigned int clk); static unsigned int ar7_set_usb_clock_notify(enum _avm_clock_id clock_id, unsigned int clk); static unsigned int ar7_set_usb_clock(unsigned int clk); static unsigned int ar7_set_dsp_clock(unsigned int clk); static unsigned int ar7_get_system_clock(void); static unsigned int ar7_get_mips_clock(void); static unsigned int ar7_get_dsp_clock(void); static unsigned int ar7_get_usb_clock(void); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _valid_clk { unsigned int pre_div; unsigned int mult; unsigned int post_div; unsigned int clk_sel; /*--- clk_sel im Bootregister ---*/ unsigned int freq; unsigned int startup; }; struct _valid_clk valid_system_clk[] = { { freq: 25000000, pre_div: 1, mult: 10, post_div: 10, clk_sel: 1 }, { freq: 50000000, pre_div: 1, mult: 10, post_div: 5, clk_sel: 1 }, { freq: 75000000, pre_div: 1, mult: 6, post_div: 2, clk_sel: 1 }, { freq: 62500000, pre_div: 1, mult: 10, post_div: 4, clk_sel: 1 }, { freq:100000000, pre_div: 1, mult: 8, post_div: 2, clk_sel: 1 }, { startup: 1, freq:125000000, pre_div: 1, mult: 5, post_div: 1, clk_sel: 1 }, { 0, 0, 0, 0 } }; #if 0 struct _valid_clk valid_mips_clk_with_dsp_xtal[] = { { freq: default_ar7_dsp_xtal * 1, pre_div: 1, mult: 1, post_div: 1, clk_sel: 0 }, { freq: default_ar7_dsp_xtal * 2, pre_div: 1, mult: 2, post_div: 1, clk_sel: 0 }, { freq: default_ar7_dsp_xtal * 3, pre_div: 1, mult: 3, post_div: 1, clk_sel: 0 }, { freq: default_ar7_dsp_xtal * 4, pre_div: 1, mult: 4, post_div: 1, clk_sel: 0 }, { freq: default_ar7_dsp_xtal * 5, pre_div: 1, mult: 5, post_div: 1, clk_sel: 0 }, { startup: 1, freq: default_ar7_dsp_xtal * 6, pre_div: 1, mult: 6, post_div: 1, clk_sel: 0}, /* Frequ: 211968000 Hz */ { freq: default_ar7_dsp_xtal * 7, pre_div: 1, mult: 7, post_div: 1, clk_sel: 0}, /* 247296000 Hz */ { 0, 0, 0, 0 } }; #endif struct _valid_clk valid_mips_clk_with_lan_xtal[] = { { freq: default_ar7_lan_xtal * 1, pre_div: 1, mult: 1, post_div: 1, clk_sel: 1}, /* 25 Mhz */ { freq: default_ar7_lan_xtal * 2, pre_div: 1, mult: 2, post_div: 1, clk_sel: 1 }, { freq: default_ar7_lan_xtal * 3, pre_div: 1, mult: 3, post_div: 1, clk_sel: 1 }, { freq: default_ar7_lan_xtal * 4, pre_div: 1, mult: 4, post_div: 1, clk_sel: 1 }, { freq: default_ar7_lan_xtal * 5, pre_div: 1, mult: 5, post_div: 1, clk_sel: 1 }, { startup: 1, freq: default_ar7_lan_xtal * 6, pre_div: 1, mult: 6, post_div: 1, clk_sel: 1 }, /* 150 MHz */ { freq: default_ar7_lan_xtal * 13 / 2, pre_div: 2, mult: 13, post_div: 1, clk_sel: 1 }, /* 162.5 MHz */ { freq: default_ar7_lan_xtal * 7, pre_div: 1, mult: 7, post_div: 1, clk_sel: 1 }, /* 175 MHz */ { freq: default_ar7_lan_xtal * 8, pre_div: 1, mult: 8, post_div: 1, clk_sel: 1 }, /* 200 MHz */ { 0, 0, 0, 0 } }; struct _valid_clk valid_dsp_clk[] = { { startup: 1, freq: default_ar7_lan_xtal * 8, pre_div: 1, mult: 8, post_div: 1, clk_sel: 1}, /* Freq: 200000000 Hz */ { freq: default_ar7_dsp_xtal * 6, pre_div: 1, mult: 6, post_div: 1, clk_sel: 0}, /* Freq: 211968000 Hz */ { freq: default_ar7_lan_xtal * 10, pre_div: 1, mult: 10, post_div: 1, clk_sel: 1}, /* Freq: 250000000 Hz */ { 0, 0, 0, 0 } }; /*--- Abgeleitet von System oder MIPS-Clock (je nach clk_sel) - freq gibt hier dies Referenz-Frequenz an ---*/ struct _valid_clk valid_usb_clk_48Mhz[] = { /*--- abgleitet von System-Clock ---*/ { freq:150000000, pre_div: 25, mult: 8, post_div: 1, clk_sel: 0 }, { freq:125000000, pre_div: 26, mult: 10, post_div: 1, clk_sel: 0 }, { freq:62500000, pre_div: 13, mult: 10, post_div: 1, clk_sel: 0 }, /*--- abgleitet von MIPS-Clock ---*/ { freq:150000000, pre_div: 25, mult: 8, post_div: 1, clk_sel: 3 }, { 0, 0, 0, 0 } }; struct _valid_clk valid_usb_clk_25Mhz[] = { /*--- abgleitet von System-Clock ---*/ { freq:150000000, pre_div: 6, mult: 1, post_div: 1, clk_sel: 0 }, { freq:125000000, pre_div: 5, mult: 1, post_div: 1, clk_sel: 0 }, { freq:62500000, pre_div: 1, mult: 2, post_div: 2, clk_sel: 0 }, /*--- abgleitet von MIPS-Clock ---*/ { freq:162500000, pre_div: 26, mult: 8, post_div: 2, clk_sel: 3 }, { 0, 0, 0, 0 } }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ union EMIF_SDRAMTimingReg ar7_SDRAM_config[3] = { /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #ifdef USE_CL2_RAMS { /*--- 125 MHz CS2 ---*/ #define EMIF_SDRAM_TIMING_125MHZ 0 Bits: { t_rfc: 10 - 1, t_rrd: 2 - 1, t_rc: 9 - 1, t_ras: 6 - 1, t_wr: 2 - 1, t_rcd: 3 - 1, t_rp: 3 - 1 } }, #define EMIF_SDRAM_TIMING_137MHZ 1 { /*--- 137,5 MHz CS2 ---*/ Bits: { t_rfc: 11 - 1, t_rrd: 2 - 1, t_rc: 9 - 1, t_ras: 6 - 1, t_wr: 2 - 1, t_rcd: 3 - 1, t_rp: 3 - 1 } }, #define EMIF_SDRAM_TIMING_150MHZ 2 { /*--- 150 MHz CS2 ---*/ Bits: { t_rfc: 12 - 1, t_rrd: 3 - 1, t_rc: 10 - 1, t_ras: 7 - 1, t_wr: 3 - 1, t_rcd: 3 - 1, t_rp: 3 - 1 } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #else { /*--- 125 MHz CS3 ---*/ #define EMIF_SDRAM_TIMING_125MHZ 0 Bits: { t_rfc: 10 - 1, t_rrd: 2 - 1, t_rc: 9 - 1, t_ras: 6 - 1, t_wr: 2 - 1, t_rcd: 3 - 1, t_rp: 3 - 1 } }, #define EMIF_SDRAM_TIMING_137MHZ 1 { /*--- 137,5 MHz CS3 ---*/ Bits: { t_rfc: 11 - 1, t_rrd: 2 - 1, t_rc: 9 - 1, t_ras: 6 - 1, t_wr: 2 - 1, t_rcd: 3 - 1, t_rp: 3 - 1 } }, #define EMIF_SDRAM_TIMING_150MHZ 2 { /*--- 150 MHz CS3 ---*/ Bits: { t_rfc: 12 - 1, t_rrd: 3 - 1, t_rc: 10 - 1, t_ras: 7 - 1, t_wr: 3 - 1, t_rcd: 3 - 1, t_rp: 3 - 1 } } #endif }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static inline unsigned int ar7_get_clockregister(enum _avm_clock_id id, struct _hw_clock *hw_clock, struct _hw_boot *hw_boot, union __clock_CR0 **CLKCR, union __clock_PLLCR **CLKPLLCR, union __clock_ACLKPLLCR1 **CLKPLLCR1, unsigned int *clk_sel) { *CLKPLLCR1 = NULL; switch(id) { case avm_clock_id_cpu: *CLKCR = &hw_clock->MCLKCR; *CLKPLLCR = &hw_clock->MCLKPLLCR; if(clk_sel) *clk_sel = hw_boot->hw_boot_config.Bits.mipspllsel; break; case avm_clock_id_system: *CLKCR = &hw_clock->SCLKCR; *CLKPLLCR = &hw_clock->SCLKPLLCR; if(clk_sel) *clk_sel = hw_boot->hw_boot_config.Bits.syspllsel; break; case avm_clock_id_usb: *CLKCR = &hw_clock->UCLKCR; *CLKPLLCR = &hw_clock->UCLKPLLCR; if(clk_sel) *clk_sel = hw_boot->hw_boot_config.Bits.usbpllsel; break; case avm_clock_id_dsp: if(hw_boot->hw_boot_adsl_pll_select.Bits.pll_0_select) { /*--- verwende APLL0 ---*/ *CLKCR = &hw_clock->ACLKCR0; *CLKPLLCR = &hw_clock->ACLKPLLCR0; } else { /*--- verwende APLL1 ---*/ *CLKCR = &hw_clock->ACLKCR1; *CLKPLLCR = NULL; *CLKPLLCR1 = &hw_clock->ACLKPLLCR1; /*--- Achtung ! anderer Registeraufbau! ---*/ } if(clk_sel) *clk_sel = hw_boot->hw_boot_config.Bits.adslpllsel; break; case avm_clock_id_vbus: /*--- kein break; ---*/ default: return -1; break; } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int ar7_clk_get_pll_factor(enum _avm_clock_id id, struct _hw_clock *hw_clock, unsigned int count){ union __clock_CR0 *CLKCR; union __clock_PLLCR *CLKPLLCR; union __clock_ACLKPLLCR1 *CLKPLLCR1; unsigned int clk_predivider; unsigned int clk_postdivider; unsigned int k, m, d, clk_sel; struct _hw_boot *AR7_hw_boot = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; if(ar7_get_clockregister(id, hw_clock, AR7_hw_boot, &CLKCR, &CLKPLLCR, &CLKPLLCR1, &clk_sel)) { return 0; } /* Pre-Divider and post-divider are 5 bit N+1 dividers */ clk_postdivider = CLKCR->Bits.postclkdiv + 1; clk_predivider = CLKCR->Bits.preclkdiv + 1; k = CLKPLLCR->Bits.pllmul + 1; DBG_TRC("[ar7_clk_get_pll_factor] %s basefreq %u prediv %u faktor %u postdiv %u clk_sel=%u plonoff=%u\n", id == avm_clock_id_non ? "avm_clock_id_non" : id == avm_clock_id_cpu ? "avm_clock_id_cpu" : id == avm_clock_id_system ? "avm_clock_id_system" : id == avm_clock_id_usb ? "avm_clock_id_usb" : id == avm_clock_id_dsp ? "avm_clock_id_dsp" : id == avm_clock_id_vbus ? "avm_clock_id_vbus" : "unknown", count, clk_predivider, k, clk_postdivider, clk_sel, CLKPLLCR->Bits.plonoff ); if(CLKPLLCR) { /*--- see TNETD7300 Device table section 1.3.3.5 page 1-37 ---*/ if(CLKPLLCR->Bits.pllndiv == 0) { m = 1; if(k == 16) { d = 4; } else { d = 2; } } else { if(CLKPLLCR->Bits.pldiv == 0) { d = 1; if(k == 16) { m = 1; } else { m = k; } } else { if((k & 1) == 0) { /*--- even ---*/ m = k - 1; d = 4; } else { /*--- odd ---*/ m = k; d = 2; } } } } else { printk("[ar7_clk_get_pll_factor] ADSLSS PLL1 ??? no calculate on ACLKPLLCR1 ???\n"); m = 1; d = 1; } count /= clk_predivider; if(AR7_hw_boot->hw_boot_config.Bits.pll_byp) { count /= clk_postdivider; return count; } count = (count * m) / d; count /= clk_postdivider; DBG_TRC("[ar7_clk_get_pll_factor] pllfreq = %u\n", count); return count; } #define DIVIDER_LOCK_TIME (10100 * 10) #define PLL_LOCK_TIME (10100 * 75) /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void ar7_clk_set_pll(enum _avm_clock_id id, struct _hw_clock *hw_clock, unsigned int enable, unsigned int mult, unsigned int pre_div, unsigned int post_div ) { int flags; volatile unsigned int temp; struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; union __clock_CR0 *CLKCR; union __clock_PLLCR *CLKPLLCR; union __clock_ACLKPLLCR1 *CLKPLLCR1; DBG_TRC("[ar7_clk_set_pll] %s enable %u prediv %u faktor=%u postdiv %u\n", id == avm_clock_id_non ? "avm_clock_id_non" : id == avm_clock_id_cpu ? "avm_clock_id_cpu" : id == avm_clock_id_system ? "avm_clock_id_system" : id == avm_clock_id_usb ? "avm_clock_id_usb" : id == avm_clock_id_dsp ? "avm_clock_id_dsp" : id == avm_clock_id_vbus ? "avm_clock_id_vbus" : "unknown", enable, pre_div, mult, post_div); if(ar7_get_clockregister(id, hw_clock, BOOT, &CLKCR, &CLKPLLCR, &CLKPLLCR1, NULL)) { return; } spin_lock_irqsave(&ar7_clock_spinlock, flags); if(enable == 0) { CLKPLLCR->Bits.plonoff = 0; /*--- PLL Off ---*/ spin_unlock_irqrestore(&ar7_clock_spinlock, flags); return; } CLKCR->Bits.postclkdiv = post_div - 1; CLKCR->Bits.preclkdiv = pre_div - 1; if(CLKPLLCR) { CLKPLLCR->Bits.pllndiv = 0; CLKPLLCR->Bits.plonoff = 1; /*--- PLL On ---*/ for(temp =0; temp < DIVIDER_LOCK_TIME; temp++); while (CLKPLLCR->Bits.status); /*--- wait for divider output to stabilise ---*/ #if 0 /*write to PLL clock register*/ if(id == avm_clock_id_system) { /* Bring DRAM out of hold */ EMIF->SDRAMBankCR.Bits.sr = 1; } #endif CLKPLLCR->Bits.pllmul = mult - 1; CLKPLLCR->Bits.pllndiv = 1; for(temp =0; temp < DIVIDER_LOCK_TIME; temp++); while (!CLKPLLCR->Bits.status); /*--- wait for divider output to stabilise ---*/ #if 0 /* Bring DRAM out of hold */ if(id == avm_clock_id_system) { /* Bring DRAM out of hold */ EMIF->SDRAMBankCR.Bits.sr = 0; } #endif } else { printk("[ar7_clk_set_pll] ADSLSS PLL1 ??? no change on ACLKPLLCR1 ???\n"); } spin_unlock_irqrestore(&ar7_clock_spinlock, flags); return; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(CONFIG_AR7_CLOCK_SWITCH) /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ar7_change_clock_read(char* buf, char **start, off_t offset, int count, int *eof, void *data) { unsigned int mips_clk = ar7_get_mips_clock(); unsigned int system_clk = ar7_get_system_clock(); unsigned int usb_clk = ar7_get_usb_clock(); unsigned int dsp_clk = ar7_get_dsp_clock(); unsigned int len; sprintf(buf, "AR7 Clock: CPU: %u.%03ukHz System: %u.%03ukHz USB: %u.%03ukHz DSP: %u.%03ukHz\n", mips_clk / 1000000, (mips_clk % 1000000) / 1000, system_clk / 1000000, (system_clk % 1000000) / 1000, usb_clk / 1000000, (usb_clk % 1000000) / 1000, dsp_clk / 1000000, (dsp_clk % 1000000) / 1000); len = strlen(buf); return len; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ar7_change_clock_write(struct file *file, const char __user *buff, unsigned long count, void *data) { char *p; unsigned int clk = 1; if(strstr(buff, "kHz")) clk = 1000; if(strstr(buff, "KHz")) clk = 1000; if(strstr(buff, "mHz")) clk = 1000 * 1000; if(strstr(buff, "MHz")) clk = 1000 * 1000; /*--- if(clk) ---*/ /*--- printk("[ar7_change_clock_write] faktor is %u\n", clk); ---*/ if((p = strstr(buff, "CPU:"))) { p += sizeof("CPU:") - 1; while(*p && (*p == ' ' || *p == '\t')) p++; clk *= simple_strtol(p, NULL, 0); /*--- printk("[ar7_change_clock_write] CPU: p=\"%s\" set to %uHz ", p, clk); ---*/ if(ar7_set_mips_clock(clk)) printk(" failed\n"); /*--- else ---*/ /*--- printk(" success\n"); ---*/ } else if((p = strstr(buff, "System:"))) { p += sizeof("System:") - 1; while(*p && (*p == ' ' || *p == '\t')) p++; clk *= simple_strtol(p, NULL, 0); /*--- printk("[ar7_change_clock_write] System: p=\"%s\" set to %uHz ", p, clk); ---*/ if(ar7_set_system_clock(clk)) printk(" failed\n"); /*--- else ---*/ /*--- printk(" success\n"); ---*/ } else if((p = strstr(buff, "USB:"))) { p += sizeof("USB:") - 1; while(*p && (*p == ' ' || *p == '\t')) p++; clk *= simple_strtol(p, NULL, 0); /*--- printk("[ar7_change_clock_write] USB: p=\"%s\" set to %uHz (%u) ", p, clk, (int)simple_strtol(p, NULL, 0)); ---*/ if(ar7_set_usb_clock(clk)) printk(" failed\n"); /*--- else ---*/ /*--- printk(" success\n"); ---*/ } else if((p = strstr(buff, "DSP:"))) { p += sizeof("DSP:") - 1; while(*p && (*p == ' ' || *p == '\t')) p++; clk *= simple_strtol(p, NULL, 0); /*--- printk("[ar7_change_clock_write] DSP: p=\"%s\" set to %uHz ", p, clk); ---*/ if(ar7_set_dsp_clock(clk)) printk(" failed\n"); /*--- else ---*/ /*--- printk(" success\n"); ---*/ } else { printk("[ar7_change_clock_write] buf=\"%s\"\n", buff); } return count; } #endif /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int __init ar7_clk_init(void) { struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; struct _valid_clk *V; spin_lock_init(&ar7_clock_spinlock); #if defined(CONFIG_AR7_CLOCK_SWITCH) spin_lock_init(&ar7_clock_switch_spinlock); ar7_system_clock_notify_first = NULL; #endif /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ V = valid_mips_clk_with_lan_xtal; printk("[ar7_clk_init]: dsl xtal %uHz lan xtal %uHz\n", V->freq, ar7_lan_xtal); while(V) { if(V->startup) { ar7_set_mips_clock(V->freq); break; } V++; } /* Initialisiere Systemclock auf 125MHz */ DBG_TRC("[ar7_clk_init]: clockmode=%s %s\n", BOOT->hw_boot_config.Bits.mips_async ? "async":"sync", BOOT->hw_boot_config.Bits.pll_byp ? "pll bypassed" : "pll on"); if(BOOT->hw_boot_config.Bits.mips_async == 0) { /*--- hardware is in synchrone mode ---*/ return 0; /* system clock nicht setzen */ } V = valid_system_clk; while(V) { if(V->startup) { ar7_set_system_clock(V->freq); ar7_set_usb_clock(48000000); return 0; } V++; } return 1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(CONFIG_AR7_CLOCK_SWITCH) static int __init ar7_clk_switch_init(void) { ar7_change_clock_entry = create_proc_entry("clocks", 06666, NULL); if(ar7_change_clock_entry) { ar7_change_clock_entry->read_proc = ar7_change_clock_read; ar7_change_clock_entry->write_proc = ar7_change_clock_write; ar7_change_clock_entry->data = NULL; } return 0; }; late_initcall(ar7_clk_switch_init); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int ar7_set_clock_notify(enum _avm_clock_id clock_id, unsigned int (*notify)(enum _avm_clock_id, unsigned int new_clk), int set_function) { struct _ar7_clk_notify_system_clock_change *aktuell = ar7_system_clock_notify_first; struct _ar7_clk_notify_system_clock_change *N; int flags; DBG_TRC("[ar7_set_clock_notify] %s notify %s 0x%p ", clock_id == avm_clock_id_non ? "avm_clock_id_non" : clock_id == avm_clock_id_cpu ? "avm_clock_id_cpu" : clock_id == avm_clock_id_system ? "avm_clock_id_system" : clock_id == avm_clock_id_usb ? "avm_clock_id_usb" : clock_id == avm_clock_id_dsp ? "avm_clock_id_dsp" : clock_id == avm_clock_id_vbus ? "avm_clock_id_vbus" : "unknown", set_function ? "enable" : "disable", notify); /*--- __print_symbol("0x%x\n", (unsigned long) notify); ---*/ if(set_function) { N = alloc_clk_listentry(); if(N == NULL) return -1; spin_lock_irqsave(&ar7_clock_switch_spinlock, flags); N->next = NULL; N->clock_id = clock_id; N->notify = notify; /*----------------------------------------------------------------------------------*\ * nicht der erste, es gibt schon einen \*----------------------------------------------------------------------------------*/ if(ar7_system_clock_notify_first) { while(aktuell->next) { aktuell = aktuell->next; } aktuell->next = N; } else { ar7_system_clock_notify_first = N; } spin_unlock_irqrestore(&ar7_clock_switch_spinlock, flags); return 0; } else { /*----------------------------------------------------------------------------------*\ * der erste und einzige \*----------------------------------------------------------------------------------*/ spin_lock_irqsave(&ar7_clock_switch_spinlock, flags); if(ar7_system_clock_notify_first == NULL) { spin_unlock_irqrestore(&ar7_clock_switch_spinlock, flags); return -1; } if((ar7_system_clock_notify_first->notify == notify) && (ar7_system_clock_notify_first->clock_id == clock_id)) { N = ar7_system_clock_notify_first; ar7_system_clock_notify_first = ar7_system_clock_notify_first->next; spin_unlock_irqrestore(&ar7_clock_switch_spinlock, flags); free_clk_listentry(N); return 0; } /*----------------------------------------------------------------------------------*\ * der erste ist es nicht, gibt es noch weitere \*----------------------------------------------------------------------------------*/ while(aktuell->next) { if(aktuell->next->notify == notify) { N = aktuell->next; aktuell->next = aktuell->next->next; spin_unlock_irqrestore(&ar7_clock_switch_spinlock, flags); free_clk_listentry(N); return 0; } aktuell = aktuell->next; } spin_unlock_irqrestore(&ar7_clock_switch_spinlock, flags); } return -1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_call_clock_notifier(enum _avm_clock_id clock_id, unsigned int clk) { struct _ar7_clk_notify_system_clock_change *aktuell = ar7_system_clock_notify_first; unsigned int ret = 0; while(aktuell) { if((aktuell->notify) && (aktuell->clock_id == clock_id)) { DBG_TRC("[] call 0x%p ", aktuell->notify); /*--- __print_symbol("0x%x\n", (unsigned long) aktuell->notify); ---*/ ret |= (aktuell->notify)(clock_id, clk); } aktuell = aktuell->next; } return ret; } #endif /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_set_mips_clock(unsigned int clk) { struct _hw_clock *ar7_clock = (struct _hw_clock *)AR7_CLOCK_BASE; struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; unsigned int mult, post_div, pre_div, clk_sel; struct _valid_clk *V, *VStart; VStart = V = valid_mips_clk_with_lan_xtal; clk_sel = BOOT->hw_boot_config.Bits.mipspllsel; while(V->freq) { if((V->freq == clk) && (V->clk_sel == clk_sel)) break; V++; } if(V->freq) { DBG_TRC("[ar7_set_mips_clock] set freq %u Hz pre_div=%u post_div=%u mult=%u clk_sel=%u\n", V->freq, V->pre_div, V->post_div, V->mult, V->clk_sel); mult = V->mult; pre_div = V->pre_div; post_div = V->post_div; } else { printk(KERN_ERR "[ar7_set_mips_clock]: possible value are:"); while(VStart->freq) { printk(KERN_ERR" %u.%u KHz", VStart->freq / 1000, VStart->freq % 1000); VStart++; } printk(KERN_ERR"\n"); return 1; } ar7_clk_set_pll(avm_clock_id_cpu, ar7_clock, 1 /* enable */, mult, pre_div, post_div) ; #ifdef CONFIG_AVM_POWERMETER PowerManagmentRessourceInfo(powerdevice_cpuclock, FREQUENZ_TO_PERCENT(V->freq, ar7_get_mips_clock())); #endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ #if defined(CONFIG_AR7_CLOCK_SWITCH) return ar7_call_clock_notifier(avm_clock_id_cpu, clk); #else /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ return 0; #endif /*--- #else ---*/ /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_set_system_clock(unsigned int clk) { struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; struct _hw_clock *ar7_clock = (struct _hw_clock *)AR7_CLOCK_BASE; unsigned int mult = 0; unsigned int pre_div = 0; unsigned int post_div = 0; unsigned int i; unsigned int sdram_timing = 0, clk_sel; if(BOOT->hw_boot_config.Bits.mips_async == 0) { /*--- hardware is in synchrone mode ---*/ if(clk != (ar7_get_mips_clock() / 2)) { return 1; } return 0; } clk_sel = BOOT->hw_boot_config.Bits.syspllsel; for(i = 0 ; valid_system_clk[i].freq ; i++) { if((valid_system_clk[i].freq == clk) && (valid_system_clk[i].clk_sel == clk_sel)){ break; } } switch(clk) { default: case 125000000: sdram_timing = ar7_SDRAM_config[EMIF_SDRAM_TIMING_125MHZ].i; break; case 137500000: sdram_timing = ar7_SDRAM_config[EMIF_SDRAM_TIMING_137MHZ].i; break; case 150000000: sdram_timing = ar7_SDRAM_config[EMIF_SDRAM_TIMING_150MHZ].i; break; } if(ar7_current_system_clock == clk) { #ifdef USE_CL2_RAMS struct EMIF_register_memory_map *EMIF = (struct EMIF_register_memory_map *)AR7_EMIF_BASE; /*--- printk("[speedup] CL%d -> CL2 \n", EMIF->SDRAMBankCR.Bits.cl ? 3 : 2); ---*/ EMIF->SDRAMBankCR.i = EMIF->SDRAMBankCR.i & ~(1 << 13); #endif /*--- #ifdef USE_CL2_RAMS ---*/ sdram_timing = 0; } else if(ar7_current_system_clock < clk) { struct EMIF_register_memory_map *EMIF = (struct EMIF_register_memory_map *)AR7_EMIF_BASE; #ifdef USE_CL2_RAMS /*--- printk("[speedup] (pre) (0x%x) CL%d -> CL2 Timing 0x%x -> 0x%x\n", ---*/ /*--- EMIF->SDRAMBankCR.i, ---*/ /*--- EMIF->SDRAMBankCR.Bits.cl ? 3 : 2, EMIF->SDRAMTimingReg.i, sdram_timing); ---*/ EMIF->SDRAMBankCR.i = EMIF->SDRAMBankCR.i & ~(1 << 13); #else /*--- #ifdef USE_CL2_RAMS ---*/ /*--- printk("[speedup] (pre) Timing 0x%x -> 0x%x\n", EMIF->SDRAMTimingReg.i, sdram_timing); ---*/ #endif /*--- #else ---*/ /*--- #ifdef USE_CL2_RAMS ---*/ EMIF->SDRAMTimingReg.i = sdram_timing; sdram_timing = 0; } if(valid_system_clk[i].freq) { mult = valid_system_clk[i].mult; pre_div = valid_system_clk[i].pre_div; post_div = valid_system_clk[i].post_div; #ifdef CONFIG_AVM_POWERMETER PowerManagmentRessourceInfo(powerdevice_systemclock, FREQUENZ_TO_PERCENT(valid_system_clk[i].freq, 150000000)); #endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ } else { printk(KERN_ERR "[ar7_set_system_clock]: possible value are:"); for(i = 0 ; valid_system_clk[i].freq ; i++) { printk(KERN_ERR" %u.%u KHz", valid_system_clk[i].freq / 1000, valid_system_clk[i].freq % 1000); } printk(KERN_ERR"\n"); return 1; } ar7_clk_set_pll(avm_clock_id_system, ar7_clock, 1 /* enable */, mult, pre_div, post_div); if(sdram_timing) { struct EMIF_register_memory_map *EMIF = (struct EMIF_register_memory_map *)AR7_EMIF_BASE; #ifdef USE_CL2_RAMS /*--- printk("[speedup] (post) (0x%x) CL%d -> CL2 Timing 0x%x -> 0x%x\n", ---*/ /*--- EMIF->SDRAMBankCR.i, ---*/ /*--- EMIF->SDRAMBankCR.Bits.cl ? 3 : 2, EMIF->SDRAMTimingReg.i, sdram_timing); ---*/ EMIF->SDRAMBankCR.i = EMIF->SDRAMBankCR.i & ~(1 << 13); #else /*--- #ifdef USE_CL2_RAMS ---*/ /*--- printk("[speedup] (post) Timing 0x%x -> 0x%x\n", EMIF->SDRAMTimingReg.i, sdram_timing); ---*/ #endif /*--- #else ---*/ /*--- #ifdef USE_CL2_RAMS ---*/ EMIF->SDRAMTimingReg.i = sdram_timing; } ar7_current_system_clock = clk; #if defined(CONFIG_AR7_CLOCK_SWITCH) return ar7_call_clock_notifier(avm_clock_id_system, clk); #else /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ return 0; #endif /*--- #else ---*/ /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(CONFIG_AR7_CLOCK_SWITCH) static unsigned int current_usb_clock = 48000000; static unsigned int ar7_set_usb_clock_notify(enum _avm_clock_id clock_id, unsigned int clk) { if(clock_id != avm_clock_id_system) return 1; return ar7_set_usb_clock(current_usb_clock); } #endif /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_set_usb_clock(unsigned int clk) { struct _hw_clock *ar7_clock = (struct _hw_clock *)AR7_CLOCK_BASE; struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; unsigned int clk_sel, refclk = 0; struct _valid_clk *pvalid; #if defined(CONFIG_AR7_CLOCK_SWITCH) ar7_set_clock_notify(avm_clock_id_system, ar7_set_usb_clock_notify, 0); /*--- deinstall ---*/ #endif /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ switch(clk) { case 25000000: pvalid = valid_usb_clk_25Mhz; break; case 48000000: pvalid = valid_usb_clk_48Mhz; break; default: printk(KERN_ERR"[ar7_set_usb_clock] invalid input-clock %d\n", clk); return 1; } if(BOOT->hw_boot_config.Bits.mips_async == 0) { /*--- hardware is in synchrone mode ---*/ ar7_clk_set_pll(avm_clock_id_system, ar7_clock, 1, 5, 1, 1); } clk_sel = BOOT->hw_boot_config.Bits.usbpllsel; switch(clk_sel) { case 0: /*--- USB_SYSPLL_SELECT ---*/ refclk = ar7_get_system_clock(); break; case 1: /*--- USB_REFCLKI_SELECT ---*/ refclk = ar7_lan_xtal; break; case 2:/*--- USB_XTAL3IN_SELECT ---*/ printk(KERN_ERR"[ar7_get_usb_clock]not supported clock-input\n"); break; case 3:/*--- USB_MIPSPLL_SELECT ---*/ refclk = ar7_get_mips_clock(); break; } while(pvalid->freq) { if((pvalid->freq == refclk) && (pvalid->clk_sel == clk_sel)) { break; } pvalid++; } if(pvalid->freq) { DBG_TRC("[ar7_set_usb_clock] usb pll input %u Hz\n", refclk); ar7_clk_set_pll(avm_clock_id_usb, ar7_clock, 1 /* enable */, pvalid->mult, pvalid->pre_div, pvalid->post_div); #if defined(CONFIG_AR7_CLOCK_SWITCH) current_usb_clock = clk; ar7_set_clock_notify(avm_clock_id_system, ar7_set_usb_clock_notify, 1); /*--- install ---*/ return ar7_call_clock_notifier(avm_clock_id_usb, clk); #else /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ return 0; #endif /*--- #else ---*/ /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ } printk(KERN_ERR"[ar7_set_usb_clock] can't set usb pll input %u Hz\n", refclk); return 1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_set_dsp_clock(unsigned int clk) { struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; struct _hw_clock *ar7_clock = (struct _hw_clock *)AR7_CLOCK_BASE; unsigned int clk_sel; struct _valid_clk *pvalid = valid_dsp_clk; clk_sel = BOOT->hw_boot_config.Bits.adslpllsel; while(pvalid->freq) { if((pvalid->freq == clk) && (pvalid->clk_sel == clk_sel)) { break; } pvalid++; } if(pvalid->freq) { BOOT->hw_boot_adsl_pll_select.Bits.pll_0_select = 1; /*--- verwende APLL0 ---*/ ar7_clk_set_pll(avm_clock_id_dsp, ar7_clock, 1, pvalid->mult, pvalid->pre_div, pvalid->post_div); #ifdef CONFIG_AVM_POWERMETER PowerManagmentRessourceInfo(powerdevice_dspclock, FREQUENZ_TO_PERCENT(clk, 250000000)); #endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ DBG_TRC("[ar7_set_dsp_clock]: clk = %u done\n", clk); return 0; } printk(KERN_ERR"[ar7_set_dsp_clock]: failed setting clk = %u\n", clk); return 1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_get_system_clock(void) { struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; struct _hw_clock *ar7_clock = (struct _hw_clock *)AR7_CLOCK_BASE; unsigned int refclk = 0, clk; unsigned int clk_sel; if(BOOT->hw_boot_config.Bits.mips_async == 0) { /*--- hardware is in synchrone mode ---*/ /*--- printk(KERN_ERR "[ar7_get_system_clock]: ar7 is synchron\n"); ---*/ clk = ar7_get_mips_clock() / 2; } else { clk_sel = BOOT->hw_boot_config.Bits.syspllsel; switch(clk_sel) { case 0: /*--- AFE_CLKl input ---*/ refclk = ar7_dsp_xtal; break; case 1: /*--- REFCLCKl input ---*/ refclk = ar7_lan_xtal; break; case 2: /*--- XTAL3IN input ---*/ printk(KERN_ERR"[ar7_get_system_clock]not supported clock-input\n"); break; case 3: /*--- MIPS-Pll output ---*/ refclk = ar7_get_mips_clock(); break; } clk = ar7_clk_get_pll_factor(avm_clock_id_system, ar7_clock, refclk); DBG_TRC("[ar7_get_system_clock]: clk_sel=%d clk = %u\n", clk_sel, clk); } return clk; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_get_mips_clock(void) { struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; struct _hw_clock *ar7_clock = (struct _hw_clock *)AR7_CLOCK_BASE; unsigned int clk, refclk = 0, clk_sel; clk_sel = BOOT->hw_boot_config.Bits.mipspllsel; switch(clk_sel) { case 0: /*--- AFE_CLKl input ---*/ refclk = ar7_dsp_xtal; break; case 1: /*--- REFCLCKl input ---*/ refclk = ar7_lan_xtal; break; case 2: /*--- XTAL3IN input ---*/ case 3: /*--- MIPS-Pll output ---*/ printk(KERN_ERR"[ar7_get_mips_clock]no supported clock-input\n"); break; } clk = ar7_clk_get_pll_factor(avm_clock_id_cpu, ar7_clock, refclk); DBG_TRC("[ar7_get_mips_clock]: clk = %u\n", clk); return clk; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_get_dsp_clock(void) { struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; struct _hw_clock *ar7_clock = (struct _hw_clock *)AR7_CLOCK_BASE; unsigned int clk, refclk = 0; unsigned int clk_sel; clk_sel = BOOT->hw_boot_config.Bits.adslpllsel; switch(clk_sel) { case 0: /*--- AFE_CLKl input ---*/ refclk = ar7_dsp_xtal; break; case 1: /*--- REFCLCKl input ---*/ refclk = ar7_lan_xtal; break; case 2: /*--- XTAL3IN input ---*/ printk(KERN_ERR"[ar7_get_dsp_clock]not supported clock-input\n"); break; case 3: /*--- MIPS-Pll output ---*/ refclk = ar7_get_mips_clock(); break; } clk = ar7_clk_get_pll_factor(avm_clock_id_dsp, ar7_clock, refclk); DBG_TRC("[ar7_get_dsp_clock]: clk_sel=%d clk=%d\n", clk_sel, clk); return clk; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int ar7_get_usb_clock(void) { struct _hw_boot *BOOT = (struct _hw_boot *)AR7_DEVICE_CONFIG_BASE; struct _hw_clock *ar7_clock = (struct _hw_clock *)AR7_CLOCK_BASE; unsigned int clk, refclk = 0; unsigned int clk_sel; clk_sel = BOOT->hw_boot_config.Bits.usbpllsel; switch(clk_sel) { case 0: /*--- USB_SYSPLL_SELECT ---*/ refclk = ar7_get_system_clock(); break; case 1: /*--- USB_REFCLKI_SELECT ---*/ refclk = ar7_lan_xtal; break; case 2:/*--- USB_XTAL3IN_SELECT ---*/ printk(KERN_ERR"[ar7_get_usb_clock]not supported clock-input\n"); break; case 3:/*--- USB_MIPSPLL_SELECT ---*/ refclk = ar7_get_mips_clock(); break; } clk = ar7_clk_get_pll_factor(avm_clock_id_usb, ar7_clock, refclk); DBG_TRC("[ar7_get_usb_clock]: clk_sel=%d clk = %u\n", clk_sel, clk); return clk; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int ar7_get_clock(enum _avm_clock_id clock_id) { switch(clock_id) { case avm_clock_id_cpu: return ar7_get_mips_clock(); case avm_clock_id_peripheral: return ar7_get_system_clock() / 2; case avm_clock_id_system: return ar7_get_system_clock(); case avm_clock_id_vbus: return ar7_get_system_clock() / 2; case avm_clock_id_usb: return ar7_get_usb_clock(); case avm_clock_id_dsp: return ar7_get_dsp_clock(); default: break; } return 1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int ar7_set_clock(enum _avm_clock_id clock_id, unsigned int clk) { switch(clock_id) { case avm_clock_id_cpu: return ar7_set_mips_clock(clk); case avm_clock_id_system: return ar7_set_system_clock(clk); case avm_clock_id_usb: return ar7_set_usb_clock(clk); case avm_clock_id_dsp: return ar7_set_dsp_clock(clk); case avm_clock_id_vbus: default: break; } return 1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(CONFIG_AR7_CLOCK_SWITCH) unsigned int ar7_get_clock_notify(enum _avm_clock_id clock_id, unsigned int (*handler)(enum _avm_clock_id, unsigned int new_clk)) { ar7_set_clock_notify(clock_id, handler, 0); /*--- deinstall ---*/ ar7_set_clock_notify(clock_id, handler, 1); /*--- install ---*/ return ar7_get_clock(clock_id); } EXPORT_SYMBOL(ar7_get_clock_notify); #endif /*--- #if defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ EXPORT_SYMBOL(ar7_get_clock); EXPORT_SYMBOL(ar7_set_clock);