1/* 2 * linux/arch/sh/boards/mpc1211/setup.c 3 * 4 * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y 5 * 6 */ 7 8#include <linux/init.h> 9#include <linux/irq.h> 10#include <linux/hdreg.h> 11#include <linux/ide.h> 12#include <linux/interrupt.h> 13#include <linux/platform_device.h> 14#include <asm/io.h> 15#include <asm/machvec.h> 16#include <asm/mpc1211/mpc1211.h> 17#include <asm/mpc1211/pci.h> 18#include <asm/mpc1211/m1543c.h> 19 20/* ALI15X3 SMBus address offsets */ 21#define SMBHSTSTS (0 + 0x3100) 22#define SMBHSTCNT (1 + 0x3100) 23#define SMBHSTSTART (2 + 0x3100) 24#define SMBHSTCMD (7 + 0x3100) 25#define SMBHSTADD (3 + 0x3100) 26#define SMBHSTDAT0 (4 + 0x3100) 27#define SMBHSTDAT1 (5 + 0x3100) 28#define SMBBLKDAT (6 + 0x3100) 29 30/* Other settings */ 31#define MAX_TIMEOUT 500 /* times 1/100 sec */ 32 33/* ALI15X3 command constants */ 34#define ALI15X3_ABORT 0x04 35#define ALI15X3_T_OUT 0x08 36#define ALI15X3_QUICK 0x00 37#define ALI15X3_BYTE 0x10 38#define ALI15X3_BYTE_DATA 0x20 39#define ALI15X3_WORD_DATA 0x30 40#define ALI15X3_BLOCK_DATA 0x40 41#define ALI15X3_BLOCK_CLR 0x80 42 43/* ALI15X3 status register bits */ 44#define ALI15X3_STS_IDLE 0x04 45#define ALI15X3_STS_BUSY 0x08 46#define ALI15X3_STS_DONE 0x10 47#define ALI15X3_STS_DEV 0x20 /* device error */ 48#define ALI15X3_STS_COLL 0x40 /* collision or no response */ 49#define ALI15X3_STS_TERM 0x80 /* terminated by abort */ 50#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */ 51 52static void __init pci_write_config(unsigned long busNo, 53 unsigned long devNo, 54 unsigned long fncNo, 55 unsigned long cnfAdd, 56 unsigned long cnfData) 57{ 58 ctrl_outl((0x80000000 59 + ((busNo & 0xff) << 16) 60 + ((devNo & 0x1f) << 11) 61 + ((fncNo & 0x07) << 8) 62 + (cnfAdd & 0xfc)), PCIPAR); 63 64 ctrl_outl(cnfData, PCIPDR); 65} 66 67/* 68 Initialize IRQ setting 69*/ 70 71static unsigned char m_irq_mask = 0xfb; 72static unsigned char s_irq_mask = 0xff; 73 74static void disable_mpc1211_irq(unsigned int irq) 75{ 76 if( irq < 8) { 77 m_irq_mask |= (1 << irq); 78 outb(m_irq_mask,I8259_M_MR); 79 } else { 80 s_irq_mask |= (1 << (irq - 8)); 81 outb(s_irq_mask,I8259_S_MR); 82 } 83 84} 85 86static void enable_mpc1211_irq(unsigned int irq) 87{ 88 if( irq < 8) { 89 m_irq_mask &= ~(1 << irq); 90 outb(m_irq_mask,I8259_M_MR); 91 } else { 92 s_irq_mask &= ~(1 << (irq - 8)); 93 outb(s_irq_mask,I8259_S_MR); 94 } 95} 96 97static inline int mpc1211_irq_real(unsigned int irq) 98{ 99 int value; 100 int irqmask; 101 102 if ( irq < 8) { 103 irqmask = 1<<irq; 104 outb(0x0b,I8259_M_CR); /* ISR register */ 105 value = inb(I8259_M_CR) & irqmask; 106 outb(0x0a,I8259_M_CR); /* back ro the IPR reg */ 107 return value; 108 } 109 irqmask = 1<<(irq - 8); 110 outb(0x0b,I8259_S_CR); /* ISR register */ 111 value = inb(I8259_S_CR) & irqmask; 112 outb(0x0a,I8259_S_CR); /* back ro the IPR reg */ 113 return value; 114} 115 116static void mask_and_ack_mpc1211(unsigned int irq) 117{ 118 if(irq < 8) { 119 if(m_irq_mask & (1<<irq)){ 120 if(!mpc1211_irq_real(irq)){ 121 atomic_inc(&irq_err_count) 122 printk("spurious 8259A interrupt: IRQ %x\n",irq); 123 } 124 } else { 125 m_irq_mask |= (1<<irq); 126 } 127 inb(I8259_M_MR); /* DUMMY */ 128 outb(m_irq_mask,I8259_M_MR); /* disable */ 129 outb(0x60+irq,I8259_M_CR); /* EOI */ 130 131 } else { 132 if(s_irq_mask & (1<<(irq - 8))){ 133 if(!mpc1211_irq_real(irq)){ 134 atomic_inc(&irq_err_count); 135 printk("spurious 8259A interrupt: IRQ %x\n",irq); 136 } 137 } else { 138 s_irq_mask |= (1<<(irq - 8)); 139 } 140 inb(I8259_S_MR); /* DUMMY */ 141 outb(s_irq_mask,I8259_S_MR); /* disable */ 142 outb(0x60+(irq-8),I8259_S_CR); /* EOI */ 143 outb(0x60+2,I8259_M_CR); 144 } 145} 146 147static void end_mpc1211_irq(unsigned int irq) 148{ 149 enable_mpc1211_irq(irq); 150} 151 152static unsigned int startup_mpc1211_irq(unsigned int irq) 153{ 154 enable_mpc1211_irq(irq); 155 return 0; 156} 157 158static void shutdown_mpc1211_irq(unsigned int irq) 159{ 160 disable_mpc1211_irq(irq); 161} 162 163static struct hw_interrupt_type mpc1211_irq_type = { 164 .typename = "MPC1211-IRQ", 165 .startup = startup_mpc1211_irq, 166 .shutdown = shutdown_mpc1211_irq, 167 .enable = enable_mpc1211_irq, 168 .disable = disable_mpc1211_irq, 169 .ack = mask_and_ack_mpc1211, 170 .end = end_mpc1211_irq 171}; 172 173static void make_mpc1211_irq(unsigned int irq) 174{ 175 irq_desc[irq].chip = &mpc1211_irq_type; 176 irq_desc[irq].status = IRQ_DISABLED; 177 irq_desc[irq].action = 0; 178 irq_desc[irq].depth = 1; 179 disable_mpc1211_irq(irq); 180} 181 182int mpc1211_irq_demux(int irq) 183{ 184 unsigned int poll; 185 186 if( irq == 2 ) { 187 outb(0x0c,I8259_M_CR); 188 poll = inb(I8259_M_CR); 189 if(poll & 0x80) { 190 irq = (poll & 0x07); 191 } 192 if( irq == 2) { 193 outb(0x0c,I8259_S_CR); 194 poll = inb(I8259_S_CR); 195 irq = (poll & 0x07) + 8; 196 } 197 } 198 return irq; 199} 200 201static void __init init_mpc1211_IRQ(void) 202{ 203 int i; 204 /* 205 * Super I/O (Just mimic PC): 206 * 1: keyboard 207 * 3: serial 1 208 * 4: serial 0 209 * 5: printer 210 * 6: floppy 211 * 8: rtc 212 * 10: lan 213 * 12: mouse 214 * 14: ide0 215 * 15: ide1 216 */ 217 218 pci_write_config(0,0,0,0x54, 0xb0b0002d); 219 outb(0x11, I8259_M_CR); /* mater icw1 edge trigger */ 220 outb(0x11, I8259_S_CR); /* slave icw1 edge trigger */ 221 outb(0x20, I8259_M_MR); /* m icw2 base vec 0x08 */ 222 outb(0x28, I8259_S_MR); /* s icw2 base vec 0x70 */ 223 outb(0x04, I8259_M_MR); /* m icw3 slave irq2 */ 224 outb(0x02, I8259_S_MR); /* s icw3 slave id */ 225 outb(0x01, I8259_M_MR); /* m icw4 non buf normal eoi*/ 226 outb(0x01, I8259_S_MR); /* s icw4 non buf normal eo1*/ 227 outb(0xfb, I8259_M_MR); /* disable irq0--irq7 */ 228 outb(0xff, I8259_S_MR); /* disable irq8--irq15 */ 229 230 for ( i=0; i < 16; i++) { 231 if(i != 2) { 232 make_mpc1211_irq(i); 233 } 234 } 235} 236 237static void delay1000(void) 238{ 239 int i; 240 241 for (i=0; i<1000; i++) 242 ctrl_delay(); 243} 244 245static int put_smb_blk(unsigned char *p, int address, int command, int no) 246{ 247 int temp; 248 int timeout; 249 int i; 250 251 outb(0xff, SMBHSTSTS); 252 temp = inb(SMBHSTSTS); 253 for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); timeout++) { 254 delay1000(); 255 temp = inb(SMBHSTSTS); 256 } 257 if (timeout >= MAX_TIMEOUT){ 258 return -1; 259 } 260 261 outb(((address & 0x7f) << 1), SMBHSTADD); 262 outb(0xc0, SMBHSTCNT); 263 outb(command & 0xff, SMBHSTCMD); 264 outb(no & 0x1f, SMBHSTDAT0); 265 266 for(i = 1; i <= no; i++) { 267 outb(*p++, SMBBLKDAT); 268 } 269 outb(0xff, SMBHSTSTART); 270 271 temp = inb(SMBHSTSTS); 272 for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)); timeout++) { 273 delay1000(); 274 temp = inb(SMBHSTSTS); 275 } 276 if (timeout >= MAX_TIMEOUT) { 277 return -2; 278 } 279 if ( temp & ALI15X3_STS_ERR ){ 280 return -3; 281 } 282 return 0; 283} 284 285static struct resource heartbeat_resources[] = { 286 [0] = { 287 .start = 0xa2000000, 288 .end = 0xa2000000 + 8 - 1, 289 .flags = IORESOURCE_MEM, 290 }, 291}; 292 293static struct platform_device heartbeat_device = { 294 .name = "heartbeat", 295 .id = -1, 296 .num_resources = ARRAY_SIZE(heartbeat_resources), 297 .resource = heartbeat_resources, 298}; 299 300static struct platform_device *mpc1211_devices[] __initdata = { 301 &heartbeat_device, 302}; 303 304static int __init mpc1211_devices_setup(void) 305{ 306 return platform_add_devices(mpc1211_devices, 307 ARRAY_SIZE(mpc1211_devices)); 308} 309__initcall(mpc1211_devices_setup); 310 311/* arch/sh/boards/mpc1211/rtc.c */ 312void mpc1211_time_init(void); 313 314static void __init mpc1211_setup(char **cmdline_p) 315{ 316 unsigned char spd_buf[128]; 317 318 __set_io_port_base(PA_PCI_IO); 319 320 pci_write_config(0,0,0,0x54, 0xb0b00000); 321 322 do { 323 outb(ALI15X3_ABORT, SMBHSTCNT); 324 spd_buf[0] = 0x0c; 325 spd_buf[1] = 0x43; 326 spd_buf[2] = 0x7f; 327 spd_buf[3] = 0x03; 328 spd_buf[4] = 0x00; 329 spd_buf[5] = 0x03; 330 spd_buf[6] = 0x00; 331 } while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0); 332 333 board_time_init = mpc1211_time_init; 334 335 return 0; 336} 337 338/* 339 * The Machine Vector 340 */ 341struct sh_machine_vector mv_mpc1211 __initmv = { 342 .mv_name = "Interface MPC-1211(CTP/PCI/MPC-SH02)", 343 .mv_setup = mpc1211_setup, 344 .mv_nr_irqs = 48, 345 .mv_irq_demux = mpc1211_irq_demux, 346 .mv_init_irq = init_mpc1211_IRQ, 347}; 348ALIAS_MV(mpc1211) 349