Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * arch/sh/boards/overdrive/time.c |
| 3 | * |
| 4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) |
| 5 | * Copyright (C) 2002 Paul Mundt (lethal@chaoticdreams.org) |
| 6 | * |
| 7 | * May be copied or modified under the terms of the GNU General Public |
| 8 | * License. See linux/COPYING for more information. |
| 9 | * |
| 10 | * STMicroelectronics Overdrive Support. |
| 11 | */ |
| 12 | |
| 13 | void od_time_init(void) |
| 14 | { |
| 15 | struct frqcr_data { |
| 16 | unsigned short frqcr; |
| 17 | struct { |
| 18 | unsigned char multiplier; |
| 19 | unsigned char divisor; |
| 20 | } factor[3]; |
| 21 | }; |
| 22 | |
| 23 | static struct frqcr_data st40_frqcr_table[] = { |
| 24 | { 0x000, {{1,1}, {1,1}, {1,2}}}, |
| 25 | { 0x002, {{1,1}, {1,1}, {1,4}}}, |
| 26 | { 0x004, {{1,1}, {1,1}, {1,8}}}, |
| 27 | { 0x008, {{1,1}, {1,2}, {1,2}}}, |
| 28 | { 0x00A, {{1,1}, {1,2}, {1,4}}}, |
| 29 | { 0x00C, {{1,1}, {1,2}, {1,8}}}, |
| 30 | { 0x011, {{1,1}, {2,3}, {1,6}}}, |
| 31 | { 0x013, {{1,1}, {2,3}, {1,3}}}, |
| 32 | { 0x01A, {{1,1}, {1,2}, {1,4}}}, |
| 33 | { 0x01C, {{1,1}, {1,2}, {1,8}}}, |
| 34 | { 0x023, {{1,1}, {2,3}, {1,3}}}, |
| 35 | { 0x02C, {{1,1}, {1,2}, {1,8}}}, |
| 36 | { 0x048, {{1,2}, {1,2}, {1,4}}}, |
| 37 | { 0x04A, {{1,2}, {1,2}, {1,6}}}, |
| 38 | { 0x04C, {{1,2}, {1,2}, {1,8}}}, |
| 39 | { 0x05A, {{1,2}, {1,3}, {1,6}}}, |
| 40 | { 0x05C, {{1,2}, {1,3}, {1,6}}}, |
| 41 | { 0x063, {{1,2}, {1,4}, {1,4}}}, |
| 42 | { 0x06C, {{1,2}, {1,4}, {1,8}}}, |
| 43 | { 0x091, {{1,3}, {1,3}, {1,6}}}, |
| 44 | { 0x093, {{1,3}, {1,3}, {1,6}}}, |
| 45 | { 0x0A3, {{1,3}, {1,6}, {1,6}}}, |
| 46 | { 0x0DA, {{1,4}, {1,4}, {1,8}}}, |
| 47 | { 0x0DC, {{1,4}, {1,4}, {1,8}}}, |
| 48 | { 0x0EC, {{1,4}, {1,8}, {1,8}}}, |
| 49 | { 0x123, {{1,4}, {1,4}, {1,8}}}, |
| 50 | { 0x16C, {{1,4}, {1,8}, {1,8}}}, |
| 51 | }; |
| 52 | |
| 53 | struct memclk_data { |
| 54 | unsigned char multiplier; |
| 55 | unsigned char divisor; |
| 56 | }; |
| 57 | static struct memclk_data st40_memclk_table[8] = { |
| 58 | {1,1}, // 000 |
| 59 | {1,2}, // 001 |
| 60 | {1,3}, // 010 |
| 61 | {2,3}, // 011 |
| 62 | {1,4}, // 100 |
| 63 | {1,6}, // 101 |
| 64 | {1,8}, // 110 |
| 65 | {1,8} // 111 |
| 66 | }; |
| 67 | |
| 68 | unsigned long pvr; |
| 69 | |
| 70 | /* |
| 71 | * This should probably be moved into the SH3 probing code, and then |
| 72 | * use the processor structure to determine which CPU we are running |
| 73 | * on. |
| 74 | */ |
| 75 | pvr = ctrl_inl(CCN_PVR); |
| 76 | printk("PVR %08x\n", pvr); |
| 77 | |
| 78 | if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) { |
| 79 | /* |
| 80 | * Unfortunatly the STB1 FRQCR values are different from the |
| 81 | * 7750 ones. |
| 82 | */ |
| 83 | struct frqcr_data *d; |
| 84 | int a; |
| 85 | unsigned long memclkcr; |
| 86 | struct memclk_data *e; |
| 87 | |
| 88 | for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) { |
| 89 | d = &st40_frqcr_table[a]; |
| 90 | if (d->frqcr == (frqcr & 0x1ff)) |
| 91 | break; |
| 92 | } |
| 93 | if (a == ARRAY_SIZE(st40_frqcr_table)) { |
| 94 | d = st40_frqcr_table; |
| 95 | printk("ERROR: Unrecognised FRQCR value, using default multipliers\n"); |
| 96 | } |
| 97 | |
| 98 | memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR); |
| 99 | e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK]; |
| 100 | |
| 101 | printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n", |
| 102 | d->factor[0].multiplier, d->factor[0].divisor, |
| 103 | d->factor[1].multiplier, d->factor[1].divisor, |
| 104 | e->multiplier, e->divisor, |
| 105 | d->factor[2].multiplier, d->factor[2].divisor); |
| 106 | |
| 107 | current_cpu_data.master_clock = current_cpu_data.module_clock * |
| 108 | d->factor[2].divisor / |
| 109 | d->factor[2].multiplier; |
| 110 | current_cpu_data.bus_clock = current_cpu_data.master_clock * |
| 111 | d->factor[1].multiplier / |
| 112 | d->factor[1].divisor; |
| 113 | current_cpu_data.memory_clock = current_cpu_data.master_clock * |
| 114 | e->multiplier / e->divisor; |
| 115 | current_cpu_data.cpu_clock = current_cpu_data.master_clock * |
| 116 | d->factor[0].multiplier / |
| 117 | d->factor[0].divisor; |
| 118 | } |
| 119 | |