1 /* 2 * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI 3 * 4 * Copyright (C) 2006-2008 Barco N.V. 5 * Derived from the Cypress cy7c67200/300 ezusb linux driver and 6 * based on multiple host controller drivers inside the linux kernel. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 21 * MA 02110-1301 USA. 22 */ 23 24 #include <asm/byteorder.h> 25 #include <linux/io.h> 26 #include <linux/usb/c67x00.h> 27 #include "c67x00.h" 28 29 #define COMM_REGS 14 30 31 struct c67x00_lcp_int_data { 32 u16 regs[COMM_REGS]; 33 }; 34 35 /* -------------------------------------------------------------------------- */ 36 /* Interface definitions */ 37 38 #define COMM_ACK 0x0FED 39 #define COMM_NAK 0xDEAD 40 41 #define COMM_RESET 0xFA50 42 #define COMM_EXEC_INT 0xCE01 43 #define COMM_INT_NUM 0x01C2 44 45 /* Registers 0 to COMM_REGS-1 */ 46 #define COMM_R(x) (0x01C4 + 2 * (x)) 47 48 #define HUSB_SIE_pCurrentTDPtr(x) ((x) ? 0x01B2 : 0x01B0) 49 #define HUSB_SIE_pTDListDone_Sem(x) ((x) ? 0x01B8 : 0x01B6) 50 #define HUSB_pEOT 0x01B4 51 52 /* Software interrupts */ 53 /* 114, 115: */ 54 #define HUSB_SIE_INIT_INT(x) ((x) ? 0x0073 : 0x0072) 55 #define HUSB_RESET_INT 0x0074 56 57 #define SUSB_INIT_INT 0x0071 58 #define SUSB_INIT_INT_LOC (SUSB_INIT_INT * 2) 59 60 /* ----------------------------------------------------------------------- 61 * HPI implementation 62 * 63 * The c67x00 chip also support control via SPI or HSS serial 64 * interfaces. However, this driver assumes that register access can 65 * be performed from IRQ context. While this is a safe assuption with 66 * the HPI interface, it is not true for the serial interfaces. 67 */ 68 69 /* HPI registers */ 70 #define HPI_DATA 0 71 #define HPI_MAILBOX 1 72 #define HPI_ADDR 2 73 #define HPI_STATUS 3 74 75 static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg) 76 { 77 return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep); 78 } 79 80 static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value) 81 { 82 __raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep); 83 } 84 85 static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg) 86 { 87 hpi_write_reg(dev, HPI_ADDR, reg); 88 return hpi_read_reg(dev, HPI_DATA); 89 } 90 91 static u16 hpi_read_word(struct c67x00_device *dev, u16 reg) 92 { 93 u16 value; 94 unsigned long flags; 95 96 spin_lock_irqsave(&dev->hpi.lock, flags); 97 value = hpi_read_word_nolock(dev, reg); 98 spin_unlock_irqrestore(&dev->hpi.lock, flags); 99 100 return value; 101 } 102 103 static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value) 104 { 105 hpi_write_reg(dev, HPI_ADDR, reg); 106 hpi_write_reg(dev, HPI_DATA, value); 107 } 108 109 static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value) 110 { 111 unsigned long flags; 112 113 spin_lock_irqsave(&dev->hpi.lock, flags); 114 hpi_write_word_nolock(dev, reg, value); 115 spin_unlock_irqrestore(&dev->hpi.lock, flags); 116 } 117 118 /* 119 * Only data is little endian, addr has cpu endianess 120 */ 121 static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr, 122 u16 *data, u16 count) 123 { 124 unsigned long flags; 125 int i; 126 127 spin_lock_irqsave(&dev->hpi.lock, flags); 128 129 hpi_write_reg(dev, HPI_ADDR, addr); 130 for (i = 0; i < count; i++) 131 hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++)); 132 133 spin_unlock_irqrestore(&dev->hpi.lock, flags); 134 } 135 136 /* 137 * Only data is little endian, addr has cpu endianess 138 */ 139 static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr, 140 u16 *data, u16 count) 141 { 142 unsigned long flags; 143 int i; 144 145 spin_lock_irqsave(&dev->hpi.lock, flags); 146 hpi_write_reg(dev, HPI_ADDR, addr); 147 for (i = 0; i < count; i++) 148 *data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA)); 149 150 spin_unlock_irqrestore(&dev->hpi.lock, flags); 151 } 152 153 static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask) 154 { 155 u16 value; 156 unsigned long flags; 157 158 spin_lock_irqsave(&dev->hpi.lock, flags); 159 value = hpi_read_word_nolock(dev, reg); 160 hpi_write_word_nolock(dev, reg, value | mask); 161 spin_unlock_irqrestore(&dev->hpi.lock, flags); 162 } 163 164 static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask) 165 { 166 u16 value; 167 unsigned long flags; 168 169 spin_lock_irqsave(&dev->hpi.lock, flags); 170 value = hpi_read_word_nolock(dev, reg); 171 hpi_write_word_nolock(dev, reg, value & ~mask); 172 spin_unlock_irqrestore(&dev->hpi.lock, flags); 173 } 174 175 static u16 hpi_recv_mbox(struct c67x00_device *dev) 176 { 177 u16 value; 178 unsigned long flags; 179 180 spin_lock_irqsave(&dev->hpi.lock, flags); 181 value = hpi_read_reg(dev, HPI_MAILBOX); 182 spin_unlock_irqrestore(&dev->hpi.lock, flags); 183 184 return value; 185 } 186 187 static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value) 188 { 189 unsigned long flags; 190 191 spin_lock_irqsave(&dev->hpi.lock, flags); 192 hpi_write_reg(dev, HPI_MAILBOX, value); 193 spin_unlock_irqrestore(&dev->hpi.lock, flags); 194 195 return value; 196 } 197 198 u16 c67x00_ll_hpi_status(struct c67x00_device *dev) 199 { 200 u16 value; 201 unsigned long flags; 202 203 spin_lock_irqsave(&dev->hpi.lock, flags); 204 value = hpi_read_reg(dev, HPI_STATUS); 205 spin_unlock_irqrestore(&dev->hpi.lock, flags); 206 207 return value; 208 } 209 210 void c67x00_ll_hpi_reg_init(struct c67x00_device *dev) 211 { 212 int i; 213 214 hpi_recv_mbox(dev); 215 c67x00_ll_hpi_status(dev); 216 hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0); 217 218 for (i = 0; i < C67X00_SIES; i++) { 219 hpi_write_word(dev, SIEMSG_REG(i), 0); 220 hpi_read_word(dev, SIEMSG_REG(i)); 221 } 222 } 223 224 void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie) 225 { 226 hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG, 227 SOFEOP_TO_HPI_EN(sie->sie_num)); 228 } 229 230 void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie) 231 { 232 hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG, 233 SOFEOP_TO_HPI_EN(sie->sie_num)); 234 } 235 236 /* -------------------------------------------------------------------------- */ 237 /* Transactions */ 238 239 static inline u16 ll_recv_msg(struct c67x00_device *dev) 240 { 241 u16 res; 242 243 res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ); 244 WARN_ON(!res); 245 246 return (res == 0) ? -EIO : 0; 247 } 248 249 /* -------------------------------------------------------------------------- */ 250 /* General functions */ 251 252 u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num) 253 { 254 u16 val; 255 256 val = hpi_read_word(dev, SIEMSG_REG(sie_num)); 257 /* clear register to allow next message */ 258 hpi_write_word(dev, SIEMSG_REG(sie_num), 0); 259 260 return val; 261 } 262 263 u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie) 264 { 265 return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)); 266 } 267 268 /** 269 * c67x00_ll_usb_clear_status - clear the USB status bits 270 */ 271 void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits) 272 { 273 hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits); 274 } 275 276 u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie) 277 { 278 return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num)); 279 } 280 281 /* -------------------------------------------------------------------------- */ 282 283 static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr, 284 struct c67x00_lcp_int_data *data) 285 { 286 int i, rc; 287 288 mutex_lock(&dev->hpi.lcp.mutex); 289 hpi_write_word(dev, COMM_INT_NUM, nr); 290 for (i = 0; i < COMM_REGS; i++) 291 hpi_write_word(dev, COMM_R(i), data->regs[i]); 292 hpi_send_mbox(dev, COMM_EXEC_INT); 293 rc = ll_recv_msg(dev); 294 mutex_unlock(&dev->hpi.lcp.mutex); 295 296 return rc; 297 } 298 299 /* -------------------------------------------------------------------------- */ 300 /* Host specific functions */ 301 302 void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value) 303 { 304 mutex_lock(&dev->hpi.lcp.mutex); 305 hpi_write_word(dev, HUSB_pEOT, value); 306 mutex_unlock(&dev->hpi.lcp.mutex); 307 } 308 309 static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie) 310 { 311 struct c67x00_device *dev = sie->dev; 312 struct c67x00_lcp_int_data data; 313 int rc; 314 315 rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data); 316 BUG_ON(rc); /* No return path for error code; crash spectacularly */ 317 } 318 319 void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port) 320 { 321 struct c67x00_device *dev = sie->dev; 322 struct c67x00_lcp_int_data data; 323 int rc; 324 325 data.regs[0] = 50; /* Reset USB port for 50ms */ 326 data.regs[1] = port | (sie->sie_num << 1); 327 rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data); 328 BUG_ON(rc); /* No return path for error code; crash spectacularly */ 329 } 330 331 void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr) 332 { 333 hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr); 334 } 335 336 u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie) 337 { 338 return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num)); 339 } 340 341 u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie) 342 { 343 return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num)); 344 } 345 346 void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie) 347 { 348 /* Set port into host mode */ 349 hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE); 350 c67x00_ll_husb_sie_init(sie); 351 /* Clear interrupts */ 352 c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK); 353 /* Check */ 354 if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE)) 355 dev_warn(sie_dev(sie), 356 "SIE %d not set to host mode\n", sie->sie_num); 357 } 358 359 void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port) 360 { 361 /* Clear connect change */ 362 c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port)); 363 364 /* Enable interrupts */ 365 hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG, 366 SOFEOP_TO_CPU_EN(sie->sie_num)); 367 hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num), 368 SOF_EOP_IRQ_EN | DONE_IRQ_EN); 369 370 /* Enable pull down transistors */ 371 hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port)); 372 } 373 374 /* -------------------------------------------------------------------------- */ 375 376 void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status) 377 { 378 if ((int_status & MBX_OUT_FLG) == 0) 379 return; 380 381 dev->hpi.lcp.last_msg = hpi_recv_mbox(dev); 382 complete(&dev->hpi.lcp.msg_received); 383 } 384 385 /* -------------------------------------------------------------------------- */ 386 387 int c67x00_ll_reset(struct c67x00_device *dev) 388 { 389 int rc; 390 391 mutex_lock(&dev->hpi.lcp.mutex); 392 hpi_send_mbox(dev, COMM_RESET); 393 rc = ll_recv_msg(dev); 394 mutex_unlock(&dev->hpi.lcp.mutex); 395 396 return rc; 397 } 398 399 /* -------------------------------------------------------------------------- */ 400 401 /** 402 * c67x00_ll_write_mem_le16 - write into c67x00 memory 403 * Only data is little endian, addr has cpu endianess. 404 */ 405 void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr, 406 void *data, int len) 407 { 408 u8 *buf = data; 409 410 /* Sanity check */ 411 if (addr + len > 0xffff) { 412 dev_err(&dev->pdev->dev, 413 "Trying to write beyond writable region!\n"); 414 return; 415 } 416 417 if (addr & 0x01) { 418 /* unaligned access */ 419 u16 tmp; 420 tmp = hpi_read_word(dev, addr - 1); 421 tmp = (tmp & 0x00ff) | (*buf++ << 8); 422 hpi_write_word(dev, addr - 1, tmp); 423 addr++; 424 len--; 425 } 426 427 hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2); 428 buf += len & ~0x01; 429 addr += len & ~0x01; 430 len &= 0x01; 431 432 if (len) { 433 u16 tmp; 434 tmp = hpi_read_word(dev, addr); 435 tmp = (tmp & 0xff00) | *buf; 436 hpi_write_word(dev, addr, tmp); 437 } 438 } 439 440 /** 441 * c67x00_ll_read_mem_le16 - read from c67x00 memory 442 * Only data is little endian, addr has cpu endianess. 443 */ 444 void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr, 445 void *data, int len) 446 { 447 u8 *buf = data; 448 449 if (addr & 0x01) { 450 /* unaligned access */ 451 u16 tmp; 452 tmp = hpi_read_word(dev, addr - 1); 453 *buf++ = (tmp >> 8) & 0x00ff; 454 addr++; 455 len--; 456 } 457 458 hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2); 459 buf += len & ~0x01; 460 addr += len & ~0x01; 461 len &= 0x01; 462 463 if (len) { 464 u16 tmp; 465 tmp = hpi_read_word(dev, addr); 466 *buf = tmp & 0x00ff; 467 } 468 } 469 470 /* -------------------------------------------------------------------------- */ 471 472 void c67x00_ll_init(struct c67x00_device *dev) 473 { 474 mutex_init(&dev->hpi.lcp.mutex); 475 init_completion(&dev->hpi.lcp.msg_received); 476 } 477 478 void c67x00_ll_release(struct c67x00_device *dev) 479 { 480 } 481