paul@33 | 1 | /* |
paul@33 | 2 | * Common routines supporting board initialisation. |
paul@33 | 3 | * |
paul@33 | 4 | * Copyright (C) 2005-2006 Ingenic Semiconductor, <jlwei@ingenic.cn> |
paul@33 | 5 | * Copyright (C) Xiangfu Liu <xiangfu.z@gmail.com> |
paul@217 | 6 | * Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk> |
paul@33 | 7 | * |
paul@63 | 8 | * This program is free software: you can redistribute it and/or modify |
paul@63 | 9 | * it under the terms of the GNU General Public License as published by |
paul@63 | 10 | * the Free Software Foundation, either version 3 of the License, or |
paul@63 | 11 | * (at your option) any later version. |
paul@33 | 12 | * |
paul@63 | 13 | * This program is distributed in the hope that it will be useful, |
paul@63 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@63 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@63 | 16 | * GNU General Public License for more details. |
paul@33 | 17 | * |
paul@63 | 18 | * You should have received a copy of the GNU General Public License |
paul@63 | 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
paul@33 | 20 | */ |
paul@33 | 21 | |
paul@33 | 22 | #include "sdram.h" |
paul@33 | 23 | #include "board.h" |
paul@33 | 24 | |
paul@195 | 25 | unsigned long get_memory_size() |
paul@33 | 26 | { |
paul@33 | 27 | unsigned int dmcr; |
paul@33 | 28 | unsigned int rows, cols, dw, banks; |
paul@33 | 29 | unsigned long size; |
paul@33 | 30 | |
paul@33 | 31 | dmcr = REG_EMC_DMCR; |
paul@33 | 32 | rows = SDRAM_ROW0 + ((dmcr & EMC_DMCR_RA_MASK) >> EMC_DMCR_RA_BIT); |
paul@33 | 33 | cols = SDRAM_COL0 + ((dmcr & EMC_DMCR_CA_MASK) >> EMC_DMCR_CA_BIT); |
paul@33 | 34 | dw = (dmcr & EMC_DMCR_BW) ? 2 : 4; |
paul@33 | 35 | banks = (dmcr & EMC_DMCR_BA) ? 4 : 2; |
paul@33 | 36 | |
paul@33 | 37 | size = (1 << (rows + cols)) * dw * banks; |
paul@33 | 38 | |
paul@33 | 39 | return size; |
paul@33 | 40 | } |
paul@33 | 41 | |
paul@33 | 42 | /* Timer routines. */ |
paul@33 | 43 | |
paul@33 | 44 | extern unsigned long timestamp; |
paul@33 | 45 | extern unsigned long lastdec; |
paul@33 | 46 | |
paul@195 | 47 | unsigned long get_timer_masked() |
paul@33 | 48 | { |
paul@33 | 49 | unsigned long now = READ_TIMER; |
paul@33 | 50 | |
paul@33 | 51 | if (lastdec <= now) { |
paul@33 | 52 | /* normal mode */ |
paul@33 | 53 | timestamp += (now - lastdec); |
paul@33 | 54 | } else { |
paul@33 | 55 | /* we have an overflow ... */ |
paul@33 | 56 | timestamp += TIMER_FDATA + now - lastdec; |
paul@33 | 57 | } |
paul@33 | 58 | lastdec = now; |
paul@33 | 59 | |
paul@33 | 60 | return timestamp; |
paul@33 | 61 | } |
paul@33 | 62 | |
paul@195 | 63 | void reset_timer_masked() |
paul@33 | 64 | { |
paul@33 | 65 | /* reset time */ |
paul@33 | 66 | lastdec = READ_TIMER; |
paul@33 | 67 | timestamp = 0; |
paul@33 | 68 | } |
paul@33 | 69 | |
paul@195 | 70 | void reset_timer() |
paul@33 | 71 | { |
paul@33 | 72 | reset_timer_masked (); |
paul@33 | 73 | } |
paul@33 | 74 | |
paul@33 | 75 | unsigned long get_timer(unsigned long base) |
paul@33 | 76 | { |
paul@33 | 77 | return get_timer_masked () - base; |
paul@33 | 78 | } |
paul@33 | 79 | |
paul@33 | 80 | void set_timer(unsigned long t) |
paul@33 | 81 | { |
paul@33 | 82 | timestamp = t; |
paul@33 | 83 | } |
paul@33 | 84 | |
paul@197 | 85 | void udelay(unsigned long usec) |
paul@33 | 86 | { |
paul@33 | 87 | unsigned long tmo,tmp; |
paul@33 | 88 | |
paul@33 | 89 | /* normalize */ |
paul@33 | 90 | if (usec >= 1000) { |
paul@33 | 91 | tmo = usec / 1000; |
paul@33 | 92 | tmo *= TIMER_HZ; |
paul@33 | 93 | tmo /= 1000; |
paul@33 | 94 | } |
paul@33 | 95 | else { |
paul@33 | 96 | if (usec >= 1) { |
paul@33 | 97 | tmo = usec * TIMER_HZ; |
paul@33 | 98 | tmo /= (1000*1000); |
paul@33 | 99 | } |
paul@33 | 100 | else |
paul@33 | 101 | tmo = 1; |
paul@33 | 102 | } |
paul@33 | 103 | |
paul@33 | 104 | /* check for rollover during this delay */ |
paul@33 | 105 | tmp = get_timer (0); |
paul@33 | 106 | if ((tmp + tmo) < tmp ) |
paul@33 | 107 | reset_timer_masked(); /* timer would roll over */ |
paul@33 | 108 | else |
paul@33 | 109 | tmo += tmp; |
paul@33 | 110 | |
paul@33 | 111 | while (get_timer_masked () < tmo); |
paul@33 | 112 | } |
paul@33 | 113 | |
paul@197 | 114 | void udelay_masked(unsigned long usec) |
paul@33 | 115 | { |
paul@33 | 116 | unsigned long tmo; |
paul@33 | 117 | unsigned long endtime; |
paul@33 | 118 | signed long diff; |
paul@33 | 119 | |
paul@33 | 120 | /* normalize */ |
paul@33 | 121 | if (usec >= 1000) { |
paul@33 | 122 | tmo = usec / 1000; |
paul@33 | 123 | tmo *= TIMER_HZ; |
paul@33 | 124 | tmo /= 1000; |
paul@33 | 125 | } else { |
paul@33 | 126 | if (usec > 1) { |
paul@33 | 127 | tmo = usec * TIMER_HZ; |
paul@33 | 128 | tmo /= (1000*1000); |
paul@33 | 129 | } else { |
paul@33 | 130 | tmo = 1; |
paul@33 | 131 | } |
paul@33 | 132 | } |
paul@33 | 133 | |
paul@33 | 134 | endtime = get_timer_masked () + tmo; |
paul@33 | 135 | |
paul@33 | 136 | do { |
paul@33 | 137 | unsigned long now = get_timer_masked (); |
paul@33 | 138 | diff = endtime - now; |
paul@33 | 139 | } while (diff >= 0); |
paul@33 | 140 | } |
paul@33 | 141 | |
paul@33 | 142 | /* |
paul@33 | 143 | * This function is derived from PowerPC code (read timebase as long long). |
paul@33 | 144 | * On MIPS it just returns the timer value. |
paul@33 | 145 | */ |
paul@195 | 146 | unsigned long long get_ticks() |
paul@33 | 147 | { |
paul@33 | 148 | return get_timer(0); |
paul@33 | 149 | } |
paul@33 | 150 | |
paul@33 | 151 | /* |
paul@33 | 152 | * This function is derived from PowerPC code (timebase clock frequency). |
paul@33 | 153 | * On MIPS it returns the number of timer ticks per second. |
paul@33 | 154 | */ |
paul@195 | 155 | unsigned long get_tbclk() |
paul@33 | 156 | { |
paul@33 | 157 | return TIMER_HZ; |
paul@33 | 158 | } |
paul@197 | 159 | |
paul@197 | 160 | /* GPIO interrupt administration. */ |
paul@197 | 161 | |
paul@217 | 162 | void gpio_clear(uint8_t gpio) |
paul@197 | 163 | { |
paul@197 | 164 | /* Clear interrupt status. */ |
paul@197 | 165 | |
paul@197 | 166 | __gpio_ack_irq(gpio); |
paul@197 | 167 | __intc_ack_irq(GPIO_IRQ); |
paul@197 | 168 | } |
paul@197 | 169 | |
paul@197 | 170 | /* Miscellaneous interrupt administration. */ |
paul@197 | 171 | |
paul@197 | 172 | void irq_clear() |
paul@197 | 173 | { |
paul@217 | 174 | uint8_t i; |
paul@197 | 175 | |
paul@197 | 176 | for (i = 0; i < 32; i++) { |
paul@197 | 177 | if (REG_INTC_IPR & (1 << i)) |
paul@197 | 178 | __intc_ack_irq(i); |
paul@197 | 179 | } |
paul@197 | 180 | } |