void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) { u32 leddc_on = 10; u32 leddc_off = 90; if (cc->setup_done) return; bcma_core_chipcommon_early_init(cc); 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) bcma_err(cc->core->bus, "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))); } cc->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc); cc->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 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 void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, const uint8_t *buf, int len) { struct nand_chip *nand_chip = mtd_to_nand(mtd); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); struct bcma_drv_cc *cc = b47n->cc; u32 ctlcode; const u32 *data = (u32 *)buf; int i; 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 */ for (i = 0; i < len; i += 4, data++) { bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data); ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE; if (i == len - 4) /* Last read goes without that */ ctlcode &= ~NCTL_CSA; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) { pr_err("%s ctl_cmd didn't work!\n", __func__); return; } } b47n->curr_column += len; }
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) { u32 maxt; maxt = bcma_chipco_watchdog_get_max_timer(cc); if (bcma_core_cc_has_pmu_watchdog(cc)) { if (ticks == 1) ticks = 2; else if (ticks > maxt) ticks = maxt; bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks); } else { struct bcma_bus *bus = cc->core->bus; if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 && bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 && bus->chipinfo.id != BCMA_CHIP_ID_BCM53018) bcma_core_set_clockmode(cc->core, ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC); if (ticks > maxt) ticks = maxt; /* instant NMI */ bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); } return ticks; }
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; }
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"); }
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) { u32 maxt; enum bcma_clkmode clkmode; maxt = bcma_chipco_watchdog_get_max_timer(cc); if (cc->capabilities & BCMA_CC_CAP_PMU) { if (ticks == 1) ticks = 2; else if (ticks > maxt) ticks = maxt; bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks); } else { clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC; bcma_core_set_clockmode(cc->core, clkmode); if (ticks > maxt) ticks = maxt; /* instant NMI */ bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); } return ticks; }
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 bcma_pmu_resources_init(struct bcma_drv_cc *cc) { struct bcma_bus *bus = cc->core->bus; u32 min_msk = 0, max_msk = 0; switch (bus->chipinfo.id) { case 0x4313: min_msk = 0x200D; max_msk = 0xFFFF; break; case 43224: case 43225: break; default: pr_err("PMU resource config unknown for device 0x%04X\n", bus->chipinfo.id); } /* Set the resource masks. */ if (min_msk) bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk); if (max_msk) bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk); }
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; }
int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) { struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip; int err; u32 freq; u16 clock; u8 w0, w1, w2, w3, w4; unsigned long chipsize; /* MiB */ u8 tbits, col_bits, col_size, row_bits, row_bsize; u32 val; nand_chip->legacy.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; nand_chip->legacy.cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl; nand_chip->legacy.dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready; b47n->nand_chip.legacy.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; b47n->nand_chip.legacy.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; b47n->nand_chip.legacy.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; b47n->nand_chip.legacy.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; b47n->nand_chip.legacy.set_features = nand_get_set_features_notsupp; b47n->nand_chip.legacy.get_features = nand_get_set_features_notsupp; nand_chip->legacy.chip_delay = 50; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ /* Enable NAND flash access */ bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG, BCMA_CC_4706_FLASHSCFG_NF1); /* Configure wait counters */ if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) { /* 400 MHz */ freq = 400000000 / 4; } else { freq = bcma_chipco_pll_read(b47n->cc, 4); freq = (freq & 0xFFF) >> 3; /* Fixed reference clock 25 MHz and m = 2 */ freq = (freq * 25000000 / 2) / 4; } clock = freq / 1000000; w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock); w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock); w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock); w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock); w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock); bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0, (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0)); /* Scan NAND */ err = nand_scan(&b47n->nand_chip, 1); if (err) { pr_err("Could not scan NAND flash: %d\n", err); goto exit; } /* Configure FLASH */ chipsize = b47n->nand_chip.chipsize >> 20; tbits = ffs(chipsize); /* find first bit set */ if (!tbits || tbits != fls(chipsize)) { pr_err("Invalid flash size: 0x%lX\n", chipsize); err = -ENOTSUPP; goto exit; } tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */ col_bits = b47n->nand_chip.page_shift + 1; col_size = (col_bits + 7) / 8; row_bits = tbits - col_bits + 1; row_bsize = (row_bits + 7) / 8; val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2; bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val); exit: if (err) bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG, ~BCMA_CC_4706_FLASHSCFG_NF1); return err; }
/* 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; }
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) { /* instant NMI */ bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); }
/* * 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; }