if (!dwsbt1->map ||
!dwsbt1->dws.mem_ops.supports_op(desc->mem, &desc->info.op_tmpl)) return -EOPNOTSUPP;
if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) return -EOPNOTSUPP;
/* * Make sure the requested region doesn't go out of the physically * mapped flash memory bounds.
*/ if (desc->info.offset + desc->info.length > dwsbt1->map_len) return -EINVAL;
return 0;
}
/* * Directly mapped SPI memory region is only accessible in the dword chunks. * That's why we have to create a dedicated read-method to copy data from there * to the passed buffer.
*/ staticvoid dw_spi_bt1_dirmap_copy_from_map(void *to, void __iomem *from, size_t len)
{
size_t shift, chunk;
u32 data;
/* * We split the copying up into the next three stages: unaligned head, * aligned body, unaligned tail.
*/
shift = (size_t)from & 0x3; if (shift) {
chunk = min_t(size_t, 4 - shift, len);
data = readl_relaxed(from - shift);
memcpy(to, (char *)&data + shift, chunk);
from += chunk;
to += chunk;
len -= chunk;
}
while (len >= 4) {
data = readl_relaxed(from);
memcpy(to, &data, 4);
from += 4;
to += 4;
len -= 4;
}
if (len) {
data = readl_relaxed(from);
memcpy(to, &data, len);
}
}
/* * Make sure the requested operation length is valid. Truncate the * length if it's greater than the length of the MMIO region.
*/ if (offs >= dwsbt1->map_len || !len) return 0;
len = min_t(size_t, len, dwsbt1->map_len - offs);
/* Collect the controller configuration required by the operation */
cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;
cfg.dfs = 8;
cfg.ndf = 4;
cfg.freq = mem->spi->max_speed_hz;
/* Make sure the corresponding CS is de-asserted on transmission */
dw_spi_set_cs(mem->spi, false);
dw_spi_enable_chip(dws, 0);
dw_spi_update_config(dws, mem->spi, &cfg);
dw_spi_umask_intr(dws, DW_SPI_INT_RXFI);
dw_spi_enable_chip(dws, 1);
/* * Enable the transparent mode of the System Boot Controller. * The SPI core IO should have been locked before calling this method * so noone would be touching the controller' registers during the * dirmap operation.
*/
ret = mux_control_select(dwsbt1->mux, BT1_BOOT_DIRMAP); if (ret) return ret;
dws->irq = platform_get_irq(pdev, 0); if (dws->irq < 0) return dws->irq;
dws->num_cs = 4;
/* * Baikal-T1 Normal SPI Controllers don't always keep up with full SPI * bus speed especially when it comes to the concurrent access to the * APB bus resources. Thus we have no choice but to set a constraint on * the SPI bus frequency for the memory operations which require to * read/write data as fast as possible.
*/
dws->max_mem_freq = 20000000U;
/* * Baikal-T1 System Boot Controller is equipped with a mux, which * switches between the directly mapped SPI flash access mode and * IO access to the DW APB SSI registers. Note the mux controller * must be setup to preserve the registers being accessible by default * (on idle-state).
*/
dwsbt1->mux = devm_mux_control_get(&pdev->dev, NULL); if (IS_ERR(dwsbt1->mux)) return PTR_ERR(dwsbt1->mux);
/* * Directly mapped SPI flash memory is a 16MB MMIO region, which can be * used to access a peripheral memory device just by reading/writing * data from/to it. Note the system APB bus will stall during each IO * from/to the dirmap region until the operation is finished. So don't * use it concurrently with time-critical tasks (like the SPI memory * operations implemented in the DW APB SSI driver).
*/ #ifdef CONFIG_SPI_DW_BT1_DIRMAP
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (mem) {
dwsbt1->map = devm_ioremap_resource(&pdev->dev, mem); if (!IS_ERR(dwsbt1->map)) {
dwsbt1->map_len = resource_size(mem);
dws->mem_ops.dirmap_create = dw_spi_bt1_dirmap_create;
dws->mem_ops.dirmap_read = dw_spi_bt1_dirmap_read;
} else {
dwsbt1->map = NULL;
}
} #endif/* CONFIG_SPI_DW_BT1_DIRMAP */
/* * There is no IRQ, no DMA and just one CS available on the System Boot * SPI controller.
*/
dws->irq = IRQ_NOTCONNECTED;
dws->num_cs = 1;
/* * Baikal-T1 System Boot SPI Controller doesn't keep up with the full * SPI bus speed due to relatively slow APB bus and races for it' * resources from different CPUs. The situation is worsen by a small * FIFOs depth (just 8 words). It works better in a single CPU mode * though, but still tends to be not fast enough at low CPU * frequencies.
*/ if (num_possible_cpus() > 1)
dws->max_mem_freq = 10000000U; else
dws->max_mem_freq = 20000000U;
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.