void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) { struct bcma_bus *bus = cc->core->bus; if (cc->early_setup_done) return; spin_lock_init(&cc->gpio_lock); if (cc->core->id.rev >= 11) cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); if (cc->core->id.rev >= 35) cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); if (cc->capabilities & BCMA_CC_CAP_PMU) bcma_pmu_early_init(cc); if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC) bcma_chipco_serial_init(cc); if (bus->hosttype == BCMA_HOSTTYPE_SOC) bcma_core_chipcommon_flash_detect(cc); cc->early_setup_done = true; }
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) { u32 leddc_on = 10; u32 leddc_off = 90; if (cc->core->id.rev >= 11) cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); if (cc->core->id.rev >= 35) cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); if (cc->core->id.rev >= 20) { bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0); bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0); } if (cc->capabilities & BCMA_CC_CAP_PMU) bcma_pmu_init(cc); if (cc->capabilities & BCMA_CC_CAP_PCTL) pr_err("Power control not implemented!\n"); if (cc->core->id.rev >= 16) { if (cc->core->bus->sprom.leddc_on_time && cc->core->bus->sprom.leddc_off_time) { leddc_on = cc->core->bus->sprom.leddc_on_time; leddc_off = cc->core->bus->sprom.leddc_off_time; } bcma_cc_write32(cc, BCMA_CC_GPIOTIMER, ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); } }
static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, u32 set) { u32 value; bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset); bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); value &= mask; value |= set; bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value); bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); }
static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct nand_chip *nand_chip) { struct mtd_info *mtd = nand_to_mtd(nand_chip); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); struct bcma_drv_cc *cc = b47n->cc; u32 tmp = 0; switch (b47n->curr_command) { case NAND_CMD_READID: if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) { pr_err("Requested invalid id_data: %d\n", b47n->curr_column); return 0; } return b47n->id_data[b47n->curr_column++]; case NAND_CMD_STATUS: if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ)) return 0; return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff; case NAND_CMD_READOOB: bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4); return tmp & 0xFF; } pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command); return 0; }
static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd) { struct nand_chip *nand_chip = mtd_to_nand(mtd); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY); }
void bcma_pmu_init(struct bcma_drv_cc *cc) { u32 pmucap; pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP); cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION); pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev, pmucap); if (cc->pmu.rev == 1) bcma_cc_mask32(cc, BCMA_CC_PMU_CTL, ~BCMA_CC_PMU_CTL_NOILPONW); else bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_NOILPONW); if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2) pr_err("Fix for 4329b0 bad LPOM state not implemented!\n"); bcma_pmu_pll_init(cc); bcma_pmu_resources_init(cc); bcma_pmu_swreg_init(cc); bcma_pmu_workarounds(cc); }
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) { if (cc->early_setup_done) return; if (cc->core->id.rev >= 11) cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); if (cc->core->id.rev >= 35) cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); if (cc->capabilities & BCMA_CC_CAP_PMU) bcma_pmu_early_init(cc); cc->early_setup_done = true; }
static void bcma_chipco_serial_init(struct bcma_drv_cc *cc) { #if IS_BUILTIN(CONFIG_BCM47XX) unsigned int irq; u32 baud_base; u32 i; unsigned int ccrev = cc->core->id.rev; struct bcma_serial_port *ports = cc->serial_ports; if (ccrev >= 11 && ccrev != 15) { baud_base = bcma_chipco_get_alp_clock(cc); if (ccrev >= 21) { /* Turn off UART clock before switching clocksource. */ bcma_cc_write32(cc, BCMA_CC_CORECTL, bcma_cc_read32(cc, BCMA_CC_CORECTL) & ~BCMA_CC_CORECTL_UARTCLKEN); } /* Set the override bit so we don't divide it */ bcma_cc_write32(cc, BCMA_CC_CORECTL, bcma_cc_read32(cc, BCMA_CC_CORECTL) | BCMA_CC_CORECTL_UARTCLK0); if (ccrev >= 21) { /* Re-enable the UART clock. */ bcma_cc_write32(cc, BCMA_CC_CORECTL, bcma_cc_read32(cc, BCMA_CC_CORECTL) | BCMA_CC_CORECTL_UARTCLKEN); } } else { bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev); return; } irq = bcma_core_irq(cc->core, 0); /* Determine the registers of the UARTs */ cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); for (i = 0; i < cc->nr_serial_ports; i++) { ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA + (i * 256); ports[i].irq = irq; ports[i].baud_base = baud_base; ports[i].reg_shift = 0; } #endif /* CONFIG_BCM47XX */ }
static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, u32 mask, u32 value) { value &= mask; value |= bcma_cc_read32(cc, offset) & ~mask; bcma_cc_write32(cc, offset, value); return value; }
static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id) { struct bcma_drv_cc *cc = dev_id; u32 val = bcma_cc_read32(cc, BCMA_CC_GPIOIN); u32 mask = bcma_cc_read32(cc, BCMA_CC_GPIOIRQ); u32 pol = bcma_cc_read32(cc, BCMA_CC_GPIOPOL); unsigned long irqs = (val ^ pol) & mask; int gpio; if (!irqs) return IRQ_NONE; for_each_set_bit(gpio, &irqs, cc->gpio.ngpio) generic_handle_irq(bcma_gpio_to_irq(&cc->gpio, gpio)); bcma_chipco_gpio_polarity(cc, irqs, val & irqs); return IRQ_HANDLED; }
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) { if (cc->core->id.rev >= 11) cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); if (cc->core->id.rev >= 35) cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); if (cc->core->id.rev >= 20) { bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0); bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0); } if (cc->capabilities & BCMA_CC_CAP_PMU) bcma_pmu_init(cc); if (cc->capabilities & BCMA_CC_CAP_PCTL) pr_err("Power control not implemented!\n"); }
static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc) { int i; for (i = 0; i < NFLASH_READY_RETRIES; i++) { if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) { if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & BCMA_CC_NFLASH_CTL_ERR) { pr_err("Error on polling\n"); return -EBUSY; } else { return 0; } } } pr_err("Polling timeout!\n"); return -EBUSY; }
static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode) { int i; bcma_cc_write32(cc, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode); for (i = 0; i < 1000; i++) { if (!(bcma_cc_read32(cc, BCMA_CC_FLASHCTL) & BCMA_CC_FLASHCTL_BUSY)) return; cpu_relax(); } bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n"); }
static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, int len) { struct nand_chip *nand_chip = mtd_to_nand(mtd); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); u32 ctlcode; u32 *dest = (u32 *)buf; int i; int toread; BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); /* Don't validate column using nand_chip->page_shift, it may be bigger * when accessing OOB */ while (len) { /* We can read maximum of 0x200 bytes at once */ toread = min(len, 0x200); /* Set page and column */ bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR, b47n->curr_column); bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR, b47n->curr_page_addr); /* Prepare to read */ ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL | NCTL_CMD0; ctlcode |= NAND_CMD_READSTART << 8; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) return; if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc)) return; /* Eventually read some data :) */ for (i = 0; i < toread; i += 4, dest++) { ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ; if (i == toread - 4) /* Last read goes without that */ ctlcode &= ~NCTL_CSA; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) return; *dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA); } b47n->curr_column += toread; len -= toread; } }
static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code) { int i = 0; bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code); for (i = 0; i < NFLASH_READY_RETRIES; i++) { if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) { i = 0; break; } } if (i) { pr_err("NFLASH control command not ready!\n"); return -EBUSY; } return 0; }
u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask) { return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask; }
u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask) { return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask; }
/* Initialize serial flash access */ int bcma_sflash_init(struct bcma_drv_cc *cc) { struct bcma_bus *bus = cc->core->bus; struct bcma_sflash *sflash = &cc->sflash; struct bcma_sflash_tbl_e *e; u32 id, id2; switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { case BCMA_CC_FLASHT_STSER: bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP); bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0); bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES); id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA); bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1); bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES); id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA); switch (id) { case 0xbf: for (e = bcma_sflash_sst_tbl; e->name; e++) { if (e->id == id2) break; } break; case 0x13: return -ENOTSUPP; default: for (e = bcma_sflash_st_tbl; e->name; e++) { if (e->id == id) break; } break; } if (!e->name) { bcma_err(bus, "Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", id, id2); return -ENOTSUPP; } break; case BCMA_CC_FLASHT_ATSER: bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS); id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c; for (e = bcma_sflash_at_tbl; e->name; e++) { if (e->id == id) break; } if (!e->name) { bcma_err(bus, "Unsupported Atmel serial flash (id: 0x%X)\n", id); return -ENOTSUPP; } break; default: bcma_err(bus, "Unsupported flash type\n"); return -ENOTSUPP; } sflash->window = BCMA_SOC_FLASH2; sflash->blocksize = e->blocksize; sflash->numblocks = e->numblocks; sflash->size = sflash->blocksize * sflash->numblocks; sflash->present = true; bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n", e->name, sflash->size / 1024, sflash->blocksize, sflash->numblocks); /* Prepare platform device, but don't register it yet. It's too early, * malloc (required by device_private_init) is not available yet. */ bcma_sflash_dev.resource[0].end = bcma_sflash_dev.resource[0].start + sflash->size; bcma_sflash_dev.dev.platform_data = sflash; return 0; }
/* * Default nand_command and nand_command_lp don't match BCM4706 hardware layout. * For example, reading chip id is performed in a non-standard way. * Setting column and page is also handled differently, we use a special * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert * standard commands would be much more complicated. */ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct nand_chip *nand_chip, unsigned command, int column, int page_addr) { struct mtd_info *mtd = nand_to_mtd(nand_chip); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); struct bcma_drv_cc *cc = b47n->cc; u32 ctlcode; int i; if (column != -1) b47n->curr_column = column; if (page_addr != -1) b47n->curr_page_addr = page_addr; switch (command) { case NAND_CMD_RESET: nand_chip->legacy.cmd_ctrl(nand_chip, command, NAND_CTRL_CLE); ndelay(100); nand_wait_ready(nand_chip); break; case NAND_CMD_READID: ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0; ctlcode |= NAND_CMD_READID; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) { pr_err("READID error\n"); break; } /* * Reading is specific, last one has to go without NCTL_CSA * bit. We don't know how many reads NAND subsystem is going * to perform, so cache everything. */ for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) { ctlcode = NCTL_CSA | NCTL_READ; if (i == ARRAY_SIZE(b47n->id_data) - 1) ctlcode &= ~NCTL_CSA; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) { pr_err("READID error\n"); break; } b47n->id_data[i] = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA) & 0xFF; } break; case NAND_CMD_STATUS: ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("STATUS command error\n"); break; case NAND_CMD_READ0: break; case NAND_CMD_READOOB: if (page_addr != -1) b47n->curr_column += mtd->writesize; break; case NAND_CMD_ERASE1: bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, b47n->curr_page_addr); ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 | NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8); if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("ERASE1 failed\n"); break; case NAND_CMD_ERASE2: break; case NAND_CMD_SEQIN: /* Set page and column */ bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR, b47n->curr_column); bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, b47n->curr_page_addr); /* Prepare to write */ ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0; ctlcode |= NAND_CMD_SEQIN; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("SEQIN failed\n"); break; case NAND_CMD_PAGEPROG: if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 | NAND_CMD_PAGEPROG)) pr_err("PAGEPROG failed\n"); if (bcm47xxnflash_ops_bcm4706_poll(cc)) pr_err("PAGEPROG not ready\n"); break; default: pr_err("Command 0x%X unsupported\n", command); break; } b47n->curr_command = command; }