/** * jz4780_nemc_num_banks() - count the number of banks referenced by a device * @dev: device to count banks for, must be a child of the NEMC. * * Return: The number of unique NEMC banks referred to by the specified NEMC * child device. Unique here means that a device that references the same bank * multiple times in its "reg" property will only count once.
*/ unsignedint jz4780_nemc_num_banks(struct device *dev)
{ const __be32 *prop; unsignedint bank, count = 0; unsignedlong referenced = 0; int i = 0;
while ((prop = of_get_address(dev->of_node, i++, NULL, NULL))) {
bank = of_read_number(prop, 1); if (!(referenced & BIT(bank))) {
referenced |= BIT(bank);
count++;
}
}
/** * jz4780_nemc_set_type() - set the type of device connected to a bank * @dev: child device of the NEMC. * @bank: bank number to configure. * @type: type of device connected to the bank.
*/ void jz4780_nemc_set_type(struct device *dev, unsignedint bank, enum jz4780_nemc_bank_type type)
{ struct jz4780_nemc *nemc = dev_get_drvdata(dev->parent);
uint32_t nfcsr;
nfcsr = readl(nemc->base + NEMC_NFCSR);
/* TODO: Support toggle NAND devices. */ switch (type) { case JZ4780_NEMC_BANK_SRAM:
nfcsr &= ~(NEMC_NFCSR_TNFEn(bank) | NEMC_NFCSR_NFEn(bank)); break; case JZ4780_NEMC_BANK_NAND:
nfcsr &= ~NEMC_NFCSR_TNFEn(bank);
nfcsr |= NEMC_NFCSR_NFEn(bank); break;
}
/** * jz4780_nemc_assert() - (de-)assert a NAND device's chip enable pin * @dev: child device of the NEMC. * @bank: bank number of device. * @assert: whether the chip enable pin should be asserted. * * (De-)asserts the chip enable pin for the NAND device connected to the * specified bank.
*/ void jz4780_nemc_assert(struct device *dev, unsignedint bank, bool assert)
{ struct jz4780_nemc *nemc = dev_get_drvdata(dev->parent);
uint32_t nfcsr;
nfcsr = readl(nemc->base + NEMC_NFCSR);
if (assert)
nfcsr |= NEMC_NFCSR_NFCEn(bank); else
nfcsr &= ~NEMC_NFCSR_NFCEn(bank);
/* * Conversion of tBP and tAW cycle counts to values supported by the * hardware (round up to the next supported value).
*/ staticconst u8 convert_tBP_tAW[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
if (!of_property_read_u32(node, "ingenic,nemc-bus-width", &val)) {
smcr &= ~NEMC_SMCR_BW_MASK; switch (val) { case 8:
smcr |= NEMC_SMCR_BW_8; break; default: /* * Earlier SoCs support a 16 bit bus width (the 4780 * does not), until those are properly supported, error.
*/
dev_err(nemc->dev, "unsupported bus width: %u\n", val); returnfalse;
}
}
if (of_property_read_u32(node, "ingenic,nemc-tAS", &val) == 0) {
smcr &= ~NEMC_SMCR_TAS_MASK;
cycles = jz4780_nemc_ns_to_cycles(nemc, val); if (cycles > nemc->soc_info->tas_tah_cycles_max) {
dev_err(nemc->dev, "tAS %u is too high (%u cycles)\n",
val, cycles); returnfalse;
}
smcr |= cycles << NEMC_SMCR_TAS_SHIFT;
}
if (of_property_read_u32(node, "ingenic,nemc-tAH", &val) == 0) {
smcr &= ~NEMC_SMCR_TAH_MASK;
cycles = jz4780_nemc_ns_to_cycles(nemc, val); if (cycles > nemc->soc_info->tas_tah_cycles_max) {
dev_err(nemc->dev, "tAH %u is too high (%u cycles)\n",
val, cycles); returnfalse;
}
smcr |= cycles << NEMC_SMCR_TAH_SHIFT;
}
if (of_property_read_u32(node, "ingenic,nemc-tBP", &val) == 0) {
smcr &= ~NEMC_SMCR_TBP_MASK;
cycles = jz4780_nemc_ns_to_cycles(nemc, val); if (cycles > 31) {
dev_err(nemc->dev, "tBP %u is too high (%u cycles)\n",
val, cycles); returnfalse;
}
nemc = devm_kzalloc(dev, sizeof(*nemc), GFP_KERNEL); if (!nemc) return -ENOMEM;
nemc->soc_info = device_get_match_data(dev); if (!nemc->soc_info) return -EINVAL;
spin_lock_init(&nemc->lock);
nemc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EINVAL;
/* * The driver currently only uses the registers up to offset * NEMC_REG_LEN. Since the EFUSE registers are in the middle of the * NEMC registers, we only request the registers we will use for now; * that way the EFUSE driver can probe too.
*/ if (!devm_request_mem_region(dev, res->start, NEMC_REG_LEN, dev_name(dev))) {
dev_err(dev, "unable to request I/O memory region\n"); return -EBUSY;
}
nemc->base = devm_ioremap(dev, res->start, NEMC_REG_LEN); if (!nemc->base) {
dev_err(dev, "failed to get I/O memory\n"); return -ENOMEM;
}
writel(0, nemc->base + NEMC_NFCSR);
nemc->clk = devm_clk_get(dev, NULL); if (IS_ERR(nemc->clk)) {
dev_err(dev, "failed to get clock\n"); return PTR_ERR(nemc->clk);
}
ret = clk_prepare_enable(nemc->clk); if (ret) {
dev_err(dev, "failed to enable clock: %d\n", ret); return ret;
}
nemc->clk_period = jz4780_nemc_clk_period(nemc); if (!nemc->clk_period) {
dev_err(dev, "failed to calculate clock period\n");
clk_disable_unprepare(nemc->clk); return -EINVAL;
}
/* * Iterate over child devices, check that they do not conflict with * each other, and register child devices for them. If a child device * has invalid properties, it is ignored and no platform device is * registered for it.
*/
for_each_child_of_node(nemc->dev->of_node, child) {
referenced = 0;
i = 0; while ((prop = of_get_address(child, i++, NULL, NULL))) {
bank = of_read_number(prop, 1); if (bank < 1 || bank >= JZ4780_NEMC_NUM_BANKS) {
dev_err(nemc->dev, "%pOF requests invalid bank %u\n",
child, bank);
/* Will continue the outer loop below. */
referenced = 0; break;
}
referenced |= BIT(bank);
}
if (!referenced) {
dev_err(nemc->dev, "%pOF has no addresses\n",
child); continue;
} elseif (nemc->banks_present & referenced) {
dev_err(nemc->dev, "%pOF conflicts with another node\n",
child); continue;
}
/* Configure bank parameters. */
for_each_set_bit(bank, &referenced, JZ4780_NEMC_NUM_BANKS) { if (!jz4780_nemc_configure_bank(nemc, bank, child)) {
referenced = 0; break;
}
}
if (referenced) { if (of_platform_device_create(child, NULL, nemc->dev))
nemc->banks_present |= referenced;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.