aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ixp2000
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ixp2000')
-rw-r--r--arch/arm/mach-ixp2000/Makefile2
-rw-r--r--arch/arm/mach-ixp2000/core.c33
-rw-r--r--arch/arm/mach-ixp2000/enp2611.c31
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x00.c4
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x01.c9
-rw-r--r--arch/arm/mach-ixp2000/pci.c6
-rw-r--r--arch/arm/mach-ixp2000/uengine.c474
7 files changed, 530 insertions, 29 deletions
diff --git a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile
index 1e6139d42a92..9621aeb61f46 100644
--- a/arch/arm/mach-ixp2000/Makefile
+++ b/arch/arm/mach-ixp2000/Makefile
@@ -1,7 +1,7 @@
1# 1#
2# Makefile for the linux kernel. 2# Makefile for the linux kernel.
3# 3#
4obj-y := core.o pci.o 4obj-y := core.o pci.o uengine.o
5obj-m := 5obj-m :=
6obj-n := 6obj-n :=
7obj- := 7obj- :=
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 01c393c504d0..c93a98b2a32c 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * arch/arm/mach-ixp2000/common.c 2 * arch/arm/mach-ixp2000/core.c
3 * 3 *
4 * Common routines used by all IXP2400/2800 based platforms. 4 * Common routines used by all IXP2400/2800 based platforms.
5 * 5 *
@@ -49,7 +49,6 @@ static unsigned long ixp2000_slowport_irq_flags;
49 *************************************************************************/ 49 *************************************************************************/
50void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg) 50void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg)
51{ 51{
52
53 spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags); 52 spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags);
54 53
55 old_cfg->CCR = *IXP2000_SLOWPORT_CCR; 54 old_cfg->CCR = *IXP2000_SLOWPORT_CCR;
@@ -62,7 +61,7 @@ void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg
62 ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC); 61 ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC);
63 ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC); 62 ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC);
64 ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR); 63 ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR);
65 ixp2000_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC); 64 ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, new_cfg->ADC);
66} 65}
67 66
68void ixp2000_release_slowport(struct slowport_cfg *old_cfg) 67void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
@@ -71,7 +70,7 @@ void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
71 ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC); 70 ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC);
72 ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC); 71 ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC);
73 ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR); 72 ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR);
74 ixp2000_reg_write(IXP2000_SLOWPORT_ADC, old_cfg->ADC); 73 ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, old_cfg->ADC);
75 74
76 spin_unlock_irqrestore(&ixp2000_slowport_lock, 75 spin_unlock_irqrestore(&ixp2000_slowport_lock,
77 ixp2000_slowport_irq_flags); 76 ixp2000_slowport_irq_flags);
@@ -145,7 +144,7 @@ void __init ixp2000_map_io(void)
145 iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); 144 iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
146 145
147 /* Set slowport to 8-bit mode. */ 146 /* Set slowport to 8-bit mode. */
148 ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1); 147 ixp2000_reg_wrb(IXP2000_SLOWPORT_FRM, 1);
149} 148}
150 149
151 150
@@ -209,7 +208,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
209 write_seqlock(&xtime_lock); 208 write_seqlock(&xtime_lock);
210 209
211 /* clear timer 1 */ 210 /* clear timer 1 */
212 ixp2000_reg_write(IXP2000_T1_CLR, 1); 211 ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
213 212
214 while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { 213 while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) {
215 timer_tick(regs); 214 timer_tick(regs);
@@ -252,12 +251,12 @@ void __init ixp2000_init_time(unsigned long tick_rate)
252 251
253 ixp2000_reg_write(IXP2000_T4_CLR, 0); 252 ixp2000_reg_write(IXP2000_T4_CLR, 0);
254 ixp2000_reg_write(IXP2000_T4_CLD, -1); 253 ixp2000_reg_write(IXP2000_T4_CLD, -1);
255 ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); 254 ixp2000_reg_wrb(IXP2000_T4_CTL, (1 << 7));
256 missing_jiffy_timer_csr = IXP2000_T4_CSR; 255 missing_jiffy_timer_csr = IXP2000_T4_CSR;
257 } else { 256 } else {
258 ixp2000_reg_write(IXP2000_T2_CLR, 0); 257 ixp2000_reg_write(IXP2000_T2_CLR, 0);
259 ixp2000_reg_write(IXP2000_T2_CLD, -1); 258 ixp2000_reg_write(IXP2000_T2_CLD, -1);
260 ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7)); 259 ixp2000_reg_wrb(IXP2000_T2_CTL, (1 << 7));
261 missing_jiffy_timer_csr = IXP2000_T2_CSR; 260 missing_jiffy_timer_csr = IXP2000_T2_CSR;
262 } 261 }
263 next_jiffy_time = 0xffffffff; 262 next_jiffy_time = 0xffffffff;
@@ -279,7 +278,7 @@ static void update_gpio_int_csrs(void)
279 ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); 278 ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
280 ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); 279 ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
281 ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); 280 ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
282 ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); 281 ixp2000_reg_wrb(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
283} 282}
284 283
285void gpio_line_config(int line, int direction) 284void gpio_line_config(int line, int direction)
@@ -297,9 +296,9 @@ void gpio_line_config(int line, int direction)
297 GPIO_IRQ_level_high &= ~(1 << line); 296 GPIO_IRQ_level_high &= ~(1 << line);
298 update_gpio_int_csrs(); 297 update_gpio_int_csrs();
299 298
300 ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line); 299 ixp2000_reg_wrb(IXP2000_GPIO_PDSR, 1 << line);
301 } else if (direction == GPIO_IN) { 300 } else if (direction == GPIO_IN) {
302 ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); 301 ixp2000_reg_wrb(IXP2000_GPIO_PDCR, 1 << line);
303 } 302 }
304 local_irq_restore(flags); 303 local_irq_restore(flags);
305} 304}
@@ -365,12 +364,12 @@ static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
365 364
366 ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); 365 ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
367 ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); 366 ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
368 ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); 367 ixp2000_reg_wrb(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
369} 368}
370 369
371static void ixp2000_GPIO_irq_mask(unsigned int irq) 370static void ixp2000_GPIO_irq_mask(unsigned int irq)
372{ 371{
373 ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); 372 ixp2000_reg_wrb(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
374} 373}
375 374
376static void ixp2000_GPIO_irq_unmask(unsigned int irq) 375static void ixp2000_GPIO_irq_unmask(unsigned int irq)
@@ -389,9 +388,9 @@ static void ixp2000_pci_irq_mask(unsigned int irq)
389{ 388{
390 unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; 389 unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
391 if (irq == IRQ_IXP2000_PCIA) 390 if (irq == IRQ_IXP2000_PCIA)
392 ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26))); 391 ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
393 else if (irq == IRQ_IXP2000_PCIB) 392 else if (irq == IRQ_IXP2000_PCIB)
394 ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27))); 393 ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
395} 394}
396 395
397static void ixp2000_pci_irq_unmask(unsigned int irq) 396static void ixp2000_pci_irq_unmask(unsigned int irq)
@@ -411,7 +410,7 @@ static struct irqchip ixp2000_pci_irq_chip = {
411 410
412static void ixp2000_irq_mask(unsigned int irq) 411static void ixp2000_irq_mask(unsigned int irq)
413{ 412{
414 ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq)); 413 ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << irq));
415} 414}
416 415
417static void ixp2000_irq_unmask(unsigned int irq) 416static void ixp2000_irq_unmask(unsigned int irq)
@@ -443,7 +442,7 @@ void __init ixp2000_init_irq(void)
443 ixp2000_reg_write(IXP2000_GPIO_INCR, -1); 442 ixp2000_reg_write(IXP2000_GPIO_INCR, -1);
444 443
445 /* clear PCI interrupt sources */ 444 /* clear PCI interrupt sources */
446 ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, 0); 445 ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, 0);
447 446
448 /* 447 /*
449 * Certain bits in the IRQ status register of the 448 * Certain bits in the IRQ status register of the
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index 643f5e1c3d93..7719c478aa84 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -64,6 +64,35 @@ static struct sys_timer enp2611_timer = {
64 64
65 65
66/************************************************************************* 66/*************************************************************************
67 * ENP-2611 I/O
68 *************************************************************************/
69static struct map_desc enp2611_io_desc[] __initdata = {
70 {
71 .virtual = ENP2611_CALEB_VIRT_BASE,
72 .physical = ENP2611_CALEB_PHYS_BASE,
73 .length = ENP2611_CALEB_SIZE,
74 .type = MT_IXP2000_DEVICE
75 }, {
76 .virtual = ENP2611_PM3386_0_VIRT_BASE,
77 .physical = ENP2611_PM3386_0_PHYS_BASE,
78 .length = ENP2611_PM3386_0_SIZE,
79 .type = MT_IXP2000_DEVICE
80 }, {
81 .virtual = ENP2611_PM3386_1_VIRT_BASE,
82 .physical = ENP2611_PM3386_1_PHYS_BASE,
83 .length = ENP2611_PM3386_1_SIZE,
84 .type = MT_IXP2000_DEVICE
85 }
86};
87
88void __init enp2611_map_io(void)
89{
90 ixp2000_map_io();
91 iotable_init(enp2611_io_desc, ARRAY_SIZE(enp2611_io_desc));
92}
93
94
95/*************************************************************************
67 * ENP-2611 PCI 96 * ENP-2611 PCI
68 *************************************************************************/ 97 *************************************************************************/
69static int enp2611_pci_setup(int nr, struct pci_sys_data *sys) 98static int enp2611_pci_setup(int nr, struct pci_sys_data *sys)
@@ -229,7 +258,7 @@ MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
229 .phys_io = IXP2000_UART_PHYS_BASE, 258 .phys_io = IXP2000_UART_PHYS_BASE,
230 .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, 259 .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
231 .boot_params = 0x00000100, 260 .boot_params = 0x00000100,
232 .map_io = ixp2000_map_io, 261 .map_io = enp2611_map_io,
233 .init_irq = ixp2000_init_irq, 262 .init_irq = ixp2000_init_irq,
234 .timer = &enp2611_timer, 263 .timer = &enp2611_timer,
235 .init_machine = enp2611_init_machine, 264 .init_machine = enp2611_init_machine,
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 05dfcb48c2b6..d628da56b4bc 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -81,7 +81,7 @@ static void ixdp2x00_irq_mask(unsigned int irq)
81 81
82 dummy = *board_irq_mask; 82 dummy = *board_irq_mask;
83 dummy |= IXP2000_BOARD_IRQ_MASK(irq); 83 dummy |= IXP2000_BOARD_IRQ_MASK(irq);
84 ixp2000_reg_write(board_irq_mask, dummy); 84 ixp2000_reg_wrb(board_irq_mask, dummy);
85 85
86#ifdef CONFIG_ARCH_IXDP2400 86#ifdef CONFIG_ARCH_IXDP2400
87 if (machine_is_ixdp2400()) 87 if (machine_is_ixdp2400())
@@ -101,7 +101,7 @@ static void ixdp2x00_irq_unmask(unsigned int irq)
101 101
102 dummy = *board_irq_mask; 102 dummy = *board_irq_mask;
103 dummy &= ~IXP2000_BOARD_IRQ_MASK(irq); 103 dummy &= ~IXP2000_BOARD_IRQ_MASK(irq);
104 ixp2000_reg_write(board_irq_mask, dummy); 104 ixp2000_reg_wrb(board_irq_mask, dummy);
105 105
106 if (machine_is_ixdp2400()) 106 if (machine_is_ixdp2400())
107 ixp2000_release_slowport(&old_cfg); 107 ixp2000_release_slowport(&old_cfg);
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index b21249908ae4..e6a882f35da2 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -51,7 +51,7 @@
51 *************************************************************************/ 51 *************************************************************************/
52static void ixdp2x01_irq_mask(unsigned int irq) 52static void ixdp2x01_irq_mask(unsigned int irq)
53{ 53{
54 ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 54 ixp2000_reg_wrb(IXDP2X01_INT_MASK_SET_REG,
55 IXP2000_BOARD_IRQ_MASK(irq)); 55 IXP2000_BOARD_IRQ_MASK(irq));
56} 56}
57 57
@@ -114,7 +114,7 @@ void __init ixdp2x01_init_irq(void)
114 114
115 /* Mask all interrupts from CPLD, disable simulation */ 115 /* Mask all interrupts from CPLD, disable simulation */
116 ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff); 116 ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff);
117 ixp2000_reg_write(IXDP2X01_INT_SIM_REG, 0); 117 ixp2000_reg_wrb(IXDP2X01_INT_SIM_REG, 0);
118 118
119 for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { 119 for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) {
120 if (irq & valid_irq_mask) { 120 if (irq & valid_irq_mask) {
@@ -299,7 +299,6 @@ struct hw_pci ixdp2x01_pci __initdata = {
299 299
300int __init ixdp2x01_pci_init(void) 300int __init ixdp2x01_pci_init(void)
301{ 301{
302
303 pci_common_init(&ixdp2x01_pci); 302 pci_common_init(&ixdp2x01_pci);
304 return 0; 303 return 0;
305} 304}
@@ -316,7 +315,7 @@ static struct flash_platform_data ixdp2x01_flash_platform_data = {
316 315
317static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) 316static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs)
318{ 317{
319 ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, 318 ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG,
320 ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN)); 319 ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN));
321 return (ofs & IXDP2X01_FLASH_WINDOW_MASK); 320 return (ofs & IXDP2X01_FLASH_WINDOW_MASK);
322} 321}
@@ -363,7 +362,7 @@ static struct platform_device *ixdp2x01_devices[] __initdata = {
363 362
364static void __init ixdp2x01_init_machine(void) 363static void __init ixdp2x01_init_machine(void)
365{ 364{
366 ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, 365 ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG,
367 (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN)); 366 (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN));
368 367
369 ixdp2x01_flash_data.nr_banks = 368 ixdp2x01_flash_data.nr_banks =
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
index 522205acb316..d4bf1e1c0031 100644
--- a/arch/arm/mach-ixp2000/pci.c
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -148,7 +148,7 @@ int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_re
148 local_irq_save(flags); 148 local_irq_save(flags);
149 temp = *(IXP2000_PCI_CONTROL); 149 temp = *(IXP2000_PCI_CONTROL);
150 if (temp & ((1 << 8) | (1 << 5))) { 150 if (temp & ((1 << 8) | (1 << 5))) {
151 ixp2000_reg_write(IXP2000_PCI_CONTROL, temp); 151 ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
152 } 152 }
153 153
154 temp = *(IXP2000_PCI_CMDSTAT); 154 temp = *(IXP2000_PCI_CMDSTAT);
@@ -178,8 +178,8 @@ clear_master_aborts(void)
178 178
179 local_irq_save(flags); 179 local_irq_save(flags);
180 temp = *(IXP2000_PCI_CONTROL); 180 temp = *(IXP2000_PCI_CONTROL);
181 if (temp & ((1 << 8) | (1 << 5))) { 181 if (temp & ((1 << 8) | (1 << 5))) {
182 ixp2000_reg_write(IXP2000_PCI_CONTROL, temp); 182 ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
183 } 183 }
184 184
185 temp = *(IXP2000_PCI_CMDSTAT); 185 temp = *(IXP2000_PCI_CMDSTAT);
diff --git a/arch/arm/mach-ixp2000/uengine.c b/arch/arm/mach-ixp2000/uengine.c
new file mode 100644
index 000000000000..43e234349d4a
--- /dev/null
+++ b/arch/arm/mach-ixp2000/uengine.c
@@ -0,0 +1,474 @@
1/*
2 * Generic library functions for the microengines found on the Intel
3 * IXP2000 series of network processors.
4 *
5 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
6 * Dedicated to Marija Kulikova.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1 of the
11 * License, or (at your option) any later version.
12 */
13
14#include <linux/config.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/module.h>
19#include <linux/string.h>
20#include <asm/hardware.h>
21#include <asm/arch/ixp2000-regs.h>
22#include <asm/arch/uengine.h>
23#include <asm/io.h>
24
25#define USTORE_ADDRESS 0x000
26#define USTORE_DATA_LOWER 0x004
27#define USTORE_DATA_UPPER 0x008
28#define CTX_ENABLES 0x018
29#define CC_ENABLE 0x01c
30#define CSR_CTX_POINTER 0x020
31#define INDIRECT_CTX_STS 0x040
32#define ACTIVE_CTX_STS 0x044
33#define INDIRECT_CTX_SIG_EVENTS 0x048
34#define INDIRECT_CTX_WAKEUP_EVENTS 0x050
35#define NN_PUT 0x080
36#define NN_GET 0x084
37#define TIMESTAMP_LOW 0x0c0
38#define TIMESTAMP_HIGH 0x0c4
39#define T_INDEX_BYTE_INDEX 0x0f4
40#define LOCAL_CSR_STATUS 0x180
41
42u32 ixp2000_uengine_mask;
43
44static void *ixp2000_uengine_csr_area(int uengine)
45{
46 return ((void *)IXP2000_UENGINE_CSR_VIRT_BASE) + (uengine << 10);
47}
48
49/*
50 * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR
51 * space means that the microengine we tried to access was also trying
52 * to access its own CSR space on the same clock cycle as we did. When
53 * this happens, we lose the arbitration process by default, and the
54 * read or write we tried to do was not actually performed, so we try
55 * again until it succeeds.
56 */
57u32 ixp2000_uengine_csr_read(int uengine, int offset)
58{
59 void *uebase;
60 u32 *local_csr_status;
61 u32 *reg;
62 u32 value;
63
64 uebase = ixp2000_uengine_csr_area(uengine);
65
66 local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
67 reg = (u32 *)(uebase + offset);
68 do {
69 value = ixp2000_reg_read(reg);
70 } while (ixp2000_reg_read(local_csr_status) & 1);
71
72 return value;
73}
74EXPORT_SYMBOL(ixp2000_uengine_csr_read);
75
76void ixp2000_uengine_csr_write(int uengine, int offset, u32 value)
77{
78 void *uebase;
79 u32 *local_csr_status;
80 u32 *reg;
81
82 uebase = ixp2000_uengine_csr_area(uengine);
83
84 local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
85 reg = (u32 *)(uebase + offset);
86 do {
87 ixp2000_reg_write(reg, value);
88 } while (ixp2000_reg_read(local_csr_status) & 1);
89}
90EXPORT_SYMBOL(ixp2000_uengine_csr_write);
91
92void ixp2000_uengine_reset(u32 uengine_mask)
93{
94 ixp2000_reg_write(IXP2000_RESET1, uengine_mask & ixp2000_uengine_mask);
95 ixp2000_reg_write(IXP2000_RESET1, 0);
96}
97EXPORT_SYMBOL(ixp2000_uengine_reset);
98
99void ixp2000_uengine_set_mode(int uengine, u32 mode)
100{
101 /*
102 * CTL_STR_PAR_EN: unconditionally enable parity checking on
103 * control store.
104 */
105 mode |= 0x10000000;
106 ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode);
107
108 /*
109 * Enable updating of condition codes.
110 */
111 ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000);
112
113 /*
114 * Initialise other per-microengine registers.
115 */
116 ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00);
117 ixp2000_uengine_csr_write(uengine, NN_GET, 0x00);
118 ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0);
119}
120EXPORT_SYMBOL(ixp2000_uengine_set_mode);
121
122static int make_even_parity(u32 x)
123{
124 return hweight32(x) & 1;
125}
126
127static void ustore_write(int uengine, u64 insn)
128{
129 /*
130 * Generate even parity for top and bottom 20 bits.
131 */
132 insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41;
133 insn |= (u64)make_even_parity(insn & 0x000fffff) << 40;
134
135 /*
136 * Write to microstore. The second write auto-increments
137 * the USTORE_ADDRESS index register.
138 */
139 ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn);
140 ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32));
141}
142
143void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns)
144{
145 int i;
146
147 /*
148 * Start writing to microstore at address 0.
149 */
150 ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000);
151 for (i = 0; i < insns; i++) {
152 u64 insn;
153
154 insn = (((u64)ucode[0]) << 32) |
155 (((u64)ucode[1]) << 24) |
156 (((u64)ucode[2]) << 16) |
157 (((u64)ucode[3]) << 8) |
158 ((u64)ucode[4]);
159 ucode += 5;
160
161 ustore_write(uengine, insn);
162 }
163
164 /*
165 * Pad with a few NOPs at the end (to avoid the microengine
166 * aborting as it prefetches beyond the last instruction), unless
167 * we run off the end of the instruction store first, at which
168 * point the address register will wrap back to zero.
169 */
170 for (i = 0; i < 4; i++) {
171 u32 addr;
172
173 addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS);
174 if (addr == 0x80000000)
175 break;
176 ustore_write(uengine, 0xf0000c0300ULL);
177 }
178
179 /*
180 * End programming.
181 */
182 ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000);
183}
184EXPORT_SYMBOL(ixp2000_uengine_load_microcode);
185
186void ixp2000_uengine_init_context(int uengine, int context, int pc)
187{
188 /*
189 * Select the right context for indirect access.
190 */
191 ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context);
192
193 /*
194 * Initialise signal masks to immediately go to Ready state.
195 */
196 ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1);
197 ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1);
198
199 /*
200 * Set program counter.
201 */
202 ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc);
203}
204EXPORT_SYMBOL(ixp2000_uengine_init_context);
205
206void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask)
207{
208 u32 mask;
209
210 /*
211 * Enable the specified context to go to Executing state.
212 */
213 mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
214 mask |= ctx_mask << 8;
215 ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
216}
217EXPORT_SYMBOL(ixp2000_uengine_start_contexts);
218
219void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask)
220{
221 u32 mask;
222
223 /*
224 * Disable the Ready->Executing transition. Note that this
225 * does not stop the context until it voluntarily yields.
226 */
227 mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
228 mask &= ~(ctx_mask << 8);
229 ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
230}
231EXPORT_SYMBOL(ixp2000_uengine_stop_contexts);
232
233static int check_ixp_type(struct ixp2000_uengine_code *c)
234{
235 u32 product_id;
236 u32 rev;
237
238 product_id = ixp2000_reg_read(IXP2000_PRODUCT_ID);
239 if (((product_id >> 16) & 0x1f) != 0)
240 return 0;
241
242 switch ((product_id >> 8) & 0xff) {
243 case 0: /* IXP2800 */
244 if (!(c->cpu_model_bitmask & 4))
245 return 0;
246 break;
247
248 case 1: /* IXP2850 */
249 if (!(c->cpu_model_bitmask & 8))
250 return 0;
251 break;
252
253 case 2: /* IXP2400 */
254 if (!(c->cpu_model_bitmask & 2))
255 return 0;
256 break;
257
258 default:
259 return 0;
260 }
261
262 rev = product_id & 0xff;
263 if (rev < c->cpu_min_revision || rev > c->cpu_max_revision)
264 return 0;
265
266 return 1;
267}
268
269static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
270{
271 int offset;
272 int i;
273
274 offset = 0;
275
276 for (i = 0; i < 128; i++) {
277 u8 b3;
278 u8 b2;
279 u8 b1;
280 u8 b0;
281
282 b3 = (gpr_a[i] >> 24) & 0xff;
283 b2 = (gpr_a[i] >> 16) & 0xff;
284 b1 = (gpr_a[i] >> 8) & 0xff;
285 b0 = gpr_a[i] & 0xff;
286
287 // immed[@ai, (b1 << 8) | b0]
288 // 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII
289 ucode[offset++] = 0xf0;
290 ucode[offset++] = (b1 >> 4);
291 ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6);
292 ucode[offset++] = (b0 << 2);
293 ucode[offset++] = 0x80 | i;
294
295 // immed_w1[@ai, (b3 << 8) | b2]
296 // 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII
297 ucode[offset++] = 0xf4;
298 ucode[offset++] = 0x40 | (b3 >> 4);
299 ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6);
300 ucode[offset++] = (b2 << 2);
301 ucode[offset++] = 0x80 | i;
302 }
303
304 for (i = 0; i < 128; i++) {
305 u8 b3;
306 u8 b2;
307 u8 b1;
308 u8 b0;
309
310 b3 = (gpr_b[i] >> 24) & 0xff;
311 b2 = (gpr_b[i] >> 16) & 0xff;
312 b1 = (gpr_b[i] >> 8) & 0xff;
313 b0 = gpr_b[i] & 0xff;
314
315 // immed[@bi, (b1 << 8) | b0]
316 // 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV
317 ucode[offset++] = 0xf0;
318 ucode[offset++] = (b1 >> 4);
319 ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6);
320 ucode[offset++] = (i << 2) | 0x03;
321 ucode[offset++] = b0;
322
323 // immed_w1[@bi, (b3 << 8) | b2]
324 // 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV
325 ucode[offset++] = 0xf4;
326 ucode[offset++] = 0x40 | (b3 >> 4);
327 ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6);
328 ucode[offset++] = (i << 2) | 0x03;
329 ucode[offset++] = b2;
330 }
331
332 // ctx_arb[kill]
333 ucode[offset++] = 0xe0;
334 ucode[offset++] = 0x00;
335 ucode[offset++] = 0x01;
336 ucode[offset++] = 0x00;
337 ucode[offset++] = 0x00;
338}
339
340static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c)
341{
342 int per_ctx_regs;
343 u32 *gpr_a;
344 u32 *gpr_b;
345 u8 *ucode;
346 int i;
347
348 gpr_a = kmalloc(128 * sizeof(u32), GFP_KERNEL);
349 gpr_b = kmalloc(128 * sizeof(u32), GFP_KERNEL);
350 ucode = kmalloc(513 * 5, GFP_KERNEL);
351 if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) {
352 kfree(ucode);
353 kfree(gpr_b);
354 kfree(gpr_a);
355 return 1;
356 }
357
358 per_ctx_regs = 16;
359 if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS)
360 per_ctx_regs = 32;
361
362 memset(gpr_a, 0, sizeof(gpr_a));
363 memset(gpr_b, 0, sizeof(gpr_b));
364 for (i = 0; i < 256; i++) {
365 struct ixp2000_reg_value *r = c->initial_reg_values + i;
366 u32 *bank;
367 int inc;
368 int j;
369
370 if (r->reg == -1)
371 break;
372
373 bank = (r->reg & 0x400) ? gpr_b : gpr_a;
374 inc = (r->reg & 0x80) ? 128 : per_ctx_regs;
375
376 j = r->reg & 0x7f;
377 while (j < 128) {
378 bank[j] = r->value;
379 j += inc;
380 }
381 }
382
383 generate_ucode(ucode, gpr_a, gpr_b);
384 ixp2000_uengine_load_microcode(uengine, ucode, 513);
385 ixp2000_uengine_init_context(uengine, 0, 0);
386 ixp2000_uengine_start_contexts(uengine, 0x01);
387 for (i = 0; i < 100; i++) {
388 u32 status;
389
390 status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS);
391 if (!(status & 0x80000000))
392 break;
393 }
394 ixp2000_uengine_stop_contexts(uengine, 0x01);
395
396 kfree(ucode);
397 kfree(gpr_b);
398 kfree(gpr_a);
399
400 return !!(i == 100);
401}
402
403int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c)
404{
405 int ctx;
406
407 if (!check_ixp_type(c))
408 return 1;
409
410 if (!(ixp2000_uengine_mask & (1 << uengine)))
411 return 1;
412
413 ixp2000_uengine_reset(1 << uengine);
414 ixp2000_uengine_set_mode(uengine, c->uengine_parameters);
415 if (set_initial_registers(uengine, c))
416 return 1;
417 ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns);
418
419 for (ctx = 0; ctx < 8; ctx++)
420 ixp2000_uengine_init_context(uengine, ctx, 0);
421
422 return 0;
423}
424EXPORT_SYMBOL(ixp2000_uengine_load);
425
426
427static int __init ixp2000_uengine_init(void)
428{
429 int uengine;
430 u32 value;
431
432 /*
433 * Determine number of microengines present.
434 */
435 switch ((ixp2000_reg_read(IXP2000_PRODUCT_ID) >> 8) & 0x1fff) {
436 case 0: /* IXP2800 */
437 case 1: /* IXP2850 */
438 ixp2000_uengine_mask = 0x00ff00ff;
439 break;
440
441 case 2: /* IXP2400 */
442 ixp2000_uengine_mask = 0x000f000f;
443 break;
444
445 default:
446 printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n",
447 (unsigned int)ixp2000_reg_read(IXP2000_PRODUCT_ID));
448 ixp2000_uengine_mask = 0x00000000;
449 break;
450 }
451
452 /*
453 * Reset microengines.
454 */
455 ixp2000_reg_write(IXP2000_RESET1, ixp2000_uengine_mask);
456 ixp2000_reg_write(IXP2000_RESET1, 0);
457
458 /*
459 * Synchronise timestamp counters across all microengines.
460 */
461 value = ixp2000_reg_read(IXP2000_MISC_CONTROL);
462 ixp2000_reg_write(IXP2000_MISC_CONTROL, value & ~0x80);
463 for (uengine = 0; uengine < 32; uengine++) {
464 if (ixp2000_uengine_mask & (1 << uengine)) {
465 ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0);
466 ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0);
467 }
468 }
469 ixp2000_reg_write(IXP2000_MISC_CONTROL, value | 0x80);
470
471 return 0;
472}
473
474subsys_initcall(ixp2000_uengine_init);