1 /* Calypso DBB internal TPU (Time Processing Unit) Driver */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <calypso/tpu.h>
30 #include <calypso/tsp.h>
32 /* Using TPU_DEBUG you will send special HLDC messages to the host PC
33 * containing the full TPU RAM content at the time you call tpu_enable() */
36 #define BASE_ADDR_TPU 0xffff1000
37 #define TPU_REG(x) (BASE_ADDR_TPU+(x))
39 #define BASE_ADDR_TPU_RAM 0xffff9000
40 #define TPU_RAM_END 0xffff97ff
43 TPU_CTRL = 0x0, /* Control & Status Register */
44 INT_CTRL = 0x2, /* Interrupt Control Register */
45 INT_STAT = 0x4, /* Interrupt Status Register */
46 TPU_OFFSET = 0xC, /* Offset operand value register */
47 TPU_SYNCHRO = 0xE, /* synchro operand value register */
52 TPU_CTRL_RESET = (1 << 0),
53 TPU_CTRL_PAGE = (1 << 1),
54 TPU_CTRL_EN = (1 << 2),
56 TPU_CTRL_DSP_EN = (1 << 4),
58 TPU_CTRL_MCU_RAM_ACC = (1 << 6),
59 TPU_CTRL_TSP_RESET = (1 << 7),
60 TPU_CTRL_IDLE = (1 << 8),
61 TPU_CTRL_WAIT = (1 << 9),
62 TPU_CTRL_CK_ENABLE = (1 << 10),
63 TPU_CTRL_FULL_WRITE = (1 << 11),
66 enum tpu_int_ctrl_bits {
67 ICTRL_MCU_FRAME = (1 << 0),
68 ICTRL_MCU_PAGE = (1 << 1),
69 ICTRL_DSP_FRAME = (1 << 2),
70 ICTRL_DSP_FRAME_FORCE = (1 << 3),
73 static uint16_t *tpu_ptr = (uint16_t *)BASE_ADDR_TPU_RAM;
76 #include <comm/sercomm.h>
77 #include <layer1/sync.h>
78 static void tpu_ram_read_en(int enable)
82 reg = readw(TPU_REG(TPU_CTRL));
84 reg |= TPU_CTRL_MCU_RAM_ACC;
86 reg &= ~TPU_CTRL_MCU_RAM_ACC;
87 writew(reg, TPU_REG(TPU_CTRL));
90 static void tpu_debug(void)
92 uint16_t *tpu_base = (uint16_t *)BASE_ADDR_TPU_RAM;
93 unsigned int tpu_size = tpu_ptr - tpu_base;
94 struct msgb *msg = sercomm_alloc_msgb(tpu_size*2);
100 /* prepend tpu memory dump with frame number */
101 fn = (uint32_t *) msgb_put(msg, sizeof(fn));
102 *fn = l1s.current_time.fn;
106 data = (uint16_t *) msgb_put(msg, tpu_size*2);
107 for (i = 0; i < tpu_size; i ++)
108 data[i] = tpu_base[i];
112 sercomm_sendmsg(SC_DLCI_DEBUG, msg);
115 static void tpu_debug(void) { }
121 /* wait for a certain control bit to be set */
122 static int tpu_wait_ctrl_bit(uint16_t bit, int set)
124 int timeout = 10*1000;
127 uint16_t reg = readw(TPU_REG(TPU_CTRL));
137 puts("Timeout while waiting for TPU ctrl bit!\n");
145 /* assert or de-assert TPU reset */
146 void tpu_reset(int active)
150 printd("tpu_reset(%u)\n", active);
151 reg = readw(TPU_REG(TPU_CTRL));
153 reg |= (TPU_CTRL_RESET|TPU_CTRL_TSP_RESET);
154 writew(reg, TPU_REG(TPU_CTRL));
155 tpu_wait_ctrl_bit(TPU_CTRL_RESET, BIT_SET);
157 reg &= ~(TPU_CTRL_RESET|TPU_CTRL_TSP_RESET);
158 writew(reg, TPU_REG(TPU_CTRL));
159 tpu_wait_ctrl_bit(TPU_CTRL_RESET, BIT_CLEAR);
163 /* Enable or Disable a new scenario loaded into the TPU */
164 void tpu_enable(int active)
166 uint16_t reg = readw(TPU_REG(TPU_CTRL));
168 printd("tpu_enable(%u)\n", active);
176 writew(reg, TPU_REG(TPU_CTRL));
178 /* After the new scenario is loaded, TPU switches the MCU-visible memory
179 * page, i.e. we can write without any danger */
186 for (i = 0; i < 100000; i++) {
187 reg = readw(TPU_REG(TPU_CTRL));
188 if (i == 0 || oldreg != reg) {
189 printd("%d TPU state: 0x%04x\n", i, reg);
197 /* Enable or Disable the clock of the TPU Module */
198 void tpu_clk_enable(int active)
200 uint16_t reg = readw(TPU_REG(TPU_CTRL));
202 printd("tpu_clk_enable(%u)\n", active);
204 reg |= TPU_CTRL_CK_ENABLE;
205 writew(reg, TPU_REG(TPU_CTRL));
206 tpu_wait_ctrl_bit(TPU_CTRL_CK_ENABLE, BIT_SET);
208 reg &= ~TPU_CTRL_CK_ENABLE;
209 writew(reg, TPU_REG(TPU_CTRL));
210 tpu_wait_ctrl_bit(TPU_CTRL_CK_ENABLE, BIT_CLEAR);
214 /* Enable Frame Interrupt generation on next frame. DSP will reset it */
215 void tpu_dsp_frameirq_enable(void)
217 uint16_t reg = readw(TPU_REG(TPU_CTRL));
218 reg |= TPU_CTRL_DSP_EN;
219 writew(reg, TPU_REG(TPU_CTRL));
221 tpu_wait_ctrl_bit(TPU_CTRL_DSP_EN, BIT_SET);
224 /* Is a Frame interrupt still pending for the DSP ? */
225 int tpu_dsp_fameirq_pending(void)
227 uint16_t reg = readw(TPU_REG(TPU_CTRL));
229 if (reg & TPU_CTRL_DSP_EN)
235 void tpu_rewind(void)
237 dputs("tpu_rewind()\n");
238 tpu_ptr = (uint16_t *) BASE_ADDR_TPU_RAM;
241 void tpu_enqueue(uint16_t instr)
243 printd("tpu_enqueue(tpu_ptr=%p, instr=0x%04x)\n", tpu_ptr, instr);
245 if (tpu_ptr > (uint16_t *) TPU_RAM_END)
246 puts("TPU enqueue beyond end of TPU memory\n");
253 /* Put TPU into Reset and enable clock */
257 /* set all TPU RAM to zero */
258 for (ptr = (uint16_t *) BASE_ADDR_TPU_RAM; ptr < (uint16_t *) TPU_RAM_END; ptr++)
261 /* Get TPU out of reset */
263 /* Disable all interrupts */
264 writeb(0x7, TPU_REG(INT_CTRL));
275 /* program a sequence of TSPACT events into the TPU */
276 for (i = 0; i < 10; i++) {
277 puts("TSP ACT enable: ");
278 tsp_act_enable(0x0001);
280 puts("TSP ACT disable: ");
281 tsp_act_disable(0x0001);
286 /* tell the chip to execute the scenario */
290 void tpu_wait_idle(void)
292 dputs("Waiting for TPU Idle ");
293 /* Wait until TPU is doing something */
295 /* Wait until TPU is idle */
296 while (readw(TPU_REG(TPU_CTRL)) & TPU_CTRL_IDLE)
301 void tpu_frame_irq_en(int mcu, int dsp)
303 uint8_t reg = readb(TPU_REG(INT_CTRL));
305 reg &= ~ICTRL_MCU_FRAME;
307 reg |= ICTRL_MCU_FRAME;
310 reg &= ~ICTRL_DSP_FRAME;
312 reg |= ICTRL_DSP_FRAME;
314 writeb(reg, TPU_REG(INT_CTRL));
317 void tpu_force_dsp_frame_irq(void)
319 uint8_t reg = readb(TPU_REG(INT_CTRL));
320 reg |= ICTRL_DSP_FRAME_FORCE;
321 writeb(reg, TPU_REG(INT_CTRL));
324 uint16_t tpu_get_offset(void)
326 return readw(TPU_REG(TPU_OFFSET));
329 uint16_t tpu_get_synchro(void)
331 return readw(TPU_REG(TPU_SYNCHRO));
334 /* add two numbers, modulo 5000, and ensure the result is positive */
335 uint16_t add_mod5000(int16_t a, int16_t b)
337 int32_t sum = (int32_t)a + (int32_t)b;
341 /* wrap around zero */