/* We may be in 23-bit addressing mode, which uses the id as the * top two address bits. So, if we're referencing a different ID, * use absolute addresses.
*/ if (((last_addr >> 21) & 0x3) != id) returnfalse;
/* remove the top two bits from any 23-bit addressing */
last_addr &= (1 << 21) - 1;
/* We know that the addresses are limited to 21 bits, so this won't
* overflow the signed rel_addr */
rel_addr = addr - last_addr; if (rel_addr > 255 || rel_addr < -256) returnfalse;
/* we have 21 bits of address max */
addr &= ((1 << 21) - 1);
/* cmd opcodes are variable length - SAME_AR is only two bits */
opcode_bits = 3;
if (check_same_address(master, id, addr)) { /* we still address the byte offset within the word */
addr_bits = 2;
opcode_bits = 2;
opcode = FSI_CMD_SAME_AR;
trace_fsi_master_acf_cmd_same_addr(master);
/* * The read/write size is encoded in the lower bits of the address * (as it must be naturally-aligned), and the following ds bit. * * size addr:1 addr:0 ds * 1 x x 0 * 2 x 0 1 * 4 0 1 1 *
*/
ds = size > 1 ? 1 : 0;
addr &= ~(size - 1); if (size == 4)
addr |= 1;
/* Ring doorbell if any */ if (master->cvic)
iowrite32(0x2, master->cvic + CVIC_TRIG_REG);
/* Wait for status to indicate completion (or error) */ do { if (timeout-- == 0) {
dev_warn(master->dev, "Timeout waiting for coprocessor completion\n"); return -ETIMEDOUT;
}
stat = ioread8(master->sram + CMD_STAT_REG);
} while(stat < STAT_COMPLETE || stat == 0xff);
if (stat == STAT_COMPLETE) return 0; switch(stat) { case STAT_ERR_INVAL_CMD: return -EINVAL; case STAT_ERR_INVAL_IRQ: return -EIO; case STAT_ERR_MTOE: return -ESHUTDOWN;
} return -ENXIO;
}
staticint clock_zeros(struct fsi_master_acf *master, int count)
{ while (count) { int rc, lcnt = min(count, 255);
if (crc) { /* * Check if it's all 1's or all 0's, that probably means * the host is off
*/ if ((rtag == 0xf && rcrc == 0xf) || (rtag == 0 && rcrc == 0)) return -ENODEV;
dev_dbg(master->dev, "Bad response CRC !\n"); return -EAGAIN;
} return 0;
}
for (i = 0; i < 512; i++) {
uint8_t v; if ((i % 16) == 0)
p = trbuf;
v = ioread8(master->sram + TRACEBUF + i);
p += sprintf(p, "%02x ", v); if (((i % 16) == 15) || v == TR_END)
dev_dbg(master->dev, "%s\n", trbuf); if (v == TR_END) break;
}
}
staticvoid setup_ast2500_cf_maps(struct fsi_master_acf *master)
{ /* * Note about byteswap setting: the bus is wired backwards, * so setting the byteswap bit actually makes the ColdFire * work "normally" for a BE processor, ie, put the MSB in * the lowest address byte. * * We thus need to set the bit for our main memory which * contains our program code. We create two mappings for * the register, one with each setting. * * Segments 2 and 3 has a "swapped" mapping (BE) * and 6 and 7 have a non-swapped mapping (LE) which allows * us to avoid byteswapping register accesses since the * registers are all LE.
*/
/* Setup segment 0 to our memory region */
regmap_write(master->scu, SCU_2500_COPRO_SEG0, master->cf_mem_addr |
SCU_2500_COPRO_SEG_SWAP);
/* Segments 2 and 3 to sysregs with byteswap (for SRAM) */
regmap_write(master->scu, SCU_2500_COPRO_SEG2, SYSREG_BASE |
SCU_2500_COPRO_SEG_SWAP);
regmap_write(master->scu, SCU_2500_COPRO_SEG3, SYSREG_BASE | 0x100000 |
SCU_2500_COPRO_SEG_SWAP);
/* And segment 6 and 7 to sysregs no byteswap */
regmap_write(master->scu, SCU_2500_COPRO_SEG6, SYSREG_BASE);
regmap_write(master->scu, SCU_2500_COPRO_SEG7, SYSREG_BASE | 0x100000);
/* Memory cachable, regs and SRAM not cachable */
regmap_write(master->scu, SCU_2500_COPRO_CACHE_CTL,
SCU_2500_COPRO_SEG0_CACHE_EN | SCU_2500_COPRO_CACHE_EN);
}
staticvoid setup_ast2400_cf_maps(struct fsi_master_acf *master)
{ /* Setup segment 0 to our memory region */
regmap_write(master->scu, SCU_2400_COPRO_SEG0, master->cf_mem_addr |
SCU_2400_COPRO_SEG_SWAP);
/* Segments 2 to sysregs with byteswap (for SRAM) */
regmap_write(master->scu, SCU_2400_COPRO_SEG2, SYSREG_BASE |
SCU_2400_COPRO_SEG_SWAP);
/* And segment 6 to sysregs no byteswap */
regmap_write(master->scu, SCU_2400_COPRO_SEG6, SYSREG_BASE);
/* Memory cachable, regs and SRAM not cachable */
regmap_write(master->scu, SCU_2400_COPRO_CACHE_CTL,
SCU_2400_COPRO_SEG0_CACHE_EN | SCU_2400_COPRO_CACHE_EN);
}
staticvoid setup_common_fw_config(struct fsi_master_acf *master, void __iomem *base)
{
iowrite16be(master->gpio_clk_vreg, base + HDR_CLOCK_GPIO_VADDR);
iowrite16be(master->gpio_clk_dreg, base + HDR_CLOCK_GPIO_DADDR);
iowrite16be(master->gpio_dat_vreg, base + HDR_DATA_GPIO_VADDR);
iowrite16be(master->gpio_dat_dreg, base + HDR_DATA_GPIO_DADDR);
iowrite16be(master->gpio_tra_vreg, base + HDR_TRANS_GPIO_VADDR);
iowrite16be(master->gpio_tra_dreg, base + HDR_TRANS_GPIO_DADDR);
iowrite8(master->gpio_clk_bit, base + HDR_CLOCK_GPIO_BIT);
iowrite8(master->gpio_dat_bit, base + HDR_DATA_GPIO_BIT);
iowrite8(master->gpio_tra_bit, base + HDR_TRANS_GPIO_BIT);
}
/* This aren't under ColdFire control, just set them up appropriately */
gpiod_direction_output(master->gpio_mux, 1);
gpiod_direction_output(master->gpio_enable, 1);
/* Those are under ColdFire control, let it configure them */
rc = aspeed_gpio_copro_grab_gpio(master->gpio_clk, &master->gpio_clk_vreg,
&master->gpio_clk_dreg, &master->gpio_clk_bit); if (rc) {
dev_err(master->dev, "failed to assign clock gpio to coprocessor\n"); return rc;
}
rc = aspeed_gpio_copro_grab_gpio(master->gpio_data, &master->gpio_dat_vreg,
&master->gpio_dat_dreg, &master->gpio_dat_bit); if (rc) {
dev_err(master->dev, "failed to assign data gpio to coprocessor\n");
aspeed_gpio_copro_release_gpio(master->gpio_clk); return rc;
}
rc = aspeed_gpio_copro_grab_gpio(master->gpio_trans, &master->gpio_tra_vreg,
&master->gpio_tra_dreg, &master->gpio_tra_bit); if (rc) {
dev_err(master->dev, "failed to assign trans gpio to coprocessor\n");
aspeed_gpio_copro_release_gpio(master->gpio_clk);
aspeed_gpio_copro_release_gpio(master->gpio_data); return rc;
} return 0;
}
/* Get the binary */
rc = request_firmware(&fw, FW_FILE_NAME, master->dev); if (rc) {
dev_err(
master->dev, "Error %d to load firmware '%s' !\n",
rc, FW_FILE_NAME); return rc;
}
/* Which image do we want ? (shared vs. split clock/data GPIOs) */ if (master->gpio_clk_vreg == master->gpio_dat_vreg)
wanted_sig = SYS_SIG_SHARED; else
wanted_sig = SYS_SIG_SPLIT;
dev_dbg(master->dev, "Looking for image sig %04x\n", wanted_sig);
/* Try to find it */ for (data = fw->data; data < (fw->data + fw->size);) {
sig = be16_to_cpup((__be16 *)(data + HDR_OFFSET + HDR_SYS_SIG));
size = be32_to_cpup((__be32 *)(data + HDR_OFFSET + HDR_FW_SIZE)); if (sig == wanted_sig) break;
data += size;
} if (sig != wanted_sig) {
dev_err(master->dev, "Failed to locate image sig %04x in FW blob\n",
wanted_sig);
rc = -ENODEV; goto release_fw;
} if (size > master->cf_mem_size) {
dev_err(master->dev, "FW size (%zd) bigger than memory reserve (%zd)\n",
fw->size, master->cf_mem_size);
rc = -ENOMEM;
} else {
memcpy_toio(master->cf_mem, data, size);
}
/* Check version and signature */
dev_info(master->dev, "ColdFire initialized, firmware v%d API v%d.%d (trace %s)\n",
fw_vers, fw_api >> 8, fw_api & 0xff,
master->trace_enabled ? "enabled" : "disabled");
if ((fw_api >> 8) != API_VERSION_MAJ) {
dev_err(master->dev, "Unsupported coprocessor API version !\n"); return -ENODEV;
}
return 0;
}
staticint copro_enable_sw_irq(struct fsi_master_acf *master)
{ int timeout;
uint32_t val;
/* * Enable coprocessor interrupt input. I've had problems getting the * value to stick, so try in a loop
*/ for (timeout = 0; timeout < 10; timeout++) {
iowrite32(0x2, master->cvic + CVIC_EN_REG);
val = ioread32(master->cvic + CVIC_EN_REG); if (val & 2) break;
msleep(1);
} if (!(val & 2)) {
dev_err(master->dev, "Failed to enable coprocessor interrupt !\n"); return -ENODEV;
} return 0;
}
staticint fsi_master_acf_setup(struct fsi_master_acf *master)
{ int timeout, rc;
uint32_t val;
/* Make sure the ColdFire is stopped */
reset_cf(master);
/* * Clear SRAM. This needs to happen before we setup the GPIOs * as we might start trying to arbitrate as soon as that happens.
*/
memset_io(master->sram, 0, SRAM_SIZE);
/* Wait for status register to indicate command completion * which signals the initialization is complete
*/ for (timeout = 0; timeout < 10; timeout++) {
val = ioread8(master->sram + CF_STARTED); if (val) break;
msleep(1);
} if (!val) {
dev_err(master->dev, "Coprocessor startup timeout !\n");
rc = -ENODEV; goto err;
}
/* Enable SW interrupt to copro if any */ if (master->cvic) {
rc = copro_enable_sw_irq(master); if (rc) goto err;
} return 0;
err: /* An error occurred, don't leave the coprocessor running */
reset_cf(master);
/* Release the GPIOs */
release_copro_gpios(master);
/* * A GPIO arbitration requestion could come in while this is * happening. To avoid problems, we disable interrupts so it * cannot preempt us on this CPU
*/
local_irq_save(flags);
/* Stop the coprocessor */
reset_cf(master);
/* We mark the copro not-started */
iowrite32(0, master->sram + CF_STARTED);
/* We mark the ARB register as having given up arbitration to * deal with a potential race with the arbitration request
*/
iowrite8(ARB_ARM_ACK, master->sram + ARB_REG);
local_irq_restore(flags);
/* Return the GPIOs to the ARM */
release_copro_gpios(master);
}
/* * There is a race (which does happen at boot time) when we get an * arbitration request as we are either about to or just starting * the coprocessor. * * To handle it, we first check if we are running. If not yet we * check whether the copro is started in the SCU. * * If it's not started, we can basically just assume we have arbitration * and return. Otherwise, we wait normally expecting for the arbitration * to eventually complete.
*/ if (ioread32(master->sram + CF_STARTED) == 0) { unsignedint reg = 0;
regmap_read(master->scu, SCU_COPRO_CTRL, ®); if (!(reg & SCU_COPRO_CLK_EN)) return 0;
}
/* Ring doorbell if any */ if (master->cvic)
iowrite32(0x2, master->cvic + CVIC_TRIG_REG);
for (timeout = 0; timeout < 10000; timeout++) {
val = ioread8(master->sram + ARB_REG); if (val != ARB_ARM_REQ) break;
udelay(1);
}
/* If it failed, override anyway */ if (val != ARB_ARM_ACK)
dev_warn(master->dev, "GPIO request arbitration timeout\n");
/* AST2400 vs. AST2500 */
master->is_ast2500 = of_device_is_compatible(mnode, "aspeed,ast2500-cf-fsi-master");
/* Grab the SCU, we'll need to access it to configure the coprocessor */ if (master->is_ast2500)
master->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu"); else
master->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2400-scu"); if (IS_ERR(master->scu)) {
dev_err(&pdev->dev, "failed to find SCU regmap\n");
rc = PTR_ERR(master->scu); goto err_free;
}
/* Grab all the GPIOs we need */
gpio = devm_gpiod_get(&pdev->dev, "clock", 0); if (IS_ERR(gpio)) {
dev_err(&pdev->dev, "failed to get clock gpio\n");
rc = PTR_ERR(gpio); goto err_free;
}
master->gpio_clk = gpio;
gpio = devm_gpiod_get(&pdev->dev, "data", 0); if (IS_ERR(gpio)) {
dev_err(&pdev->dev, "failed to get data gpio\n");
rc = PTR_ERR(gpio); goto err_free;
}
master->gpio_data = gpio;
/* Optional GPIOs */
gpio = devm_gpiod_get_optional(&pdev->dev, "trans", 0); if (IS_ERR(gpio)) {
dev_err(&pdev->dev, "failed to get trans gpio\n");
rc = PTR_ERR(gpio); goto err_free;
}
master->gpio_trans = gpio;
gpio = devm_gpiod_get_optional(&pdev->dev, "enable", 0); if (IS_ERR(gpio)) {
dev_err(&pdev->dev, "failed to get enable gpio\n");
rc = PTR_ERR(gpio); goto err_free;
}
master->gpio_enable = gpio;
gpio = devm_gpiod_get_optional(&pdev->dev, "mux", 0); if (IS_ERR(gpio)) {
dev_err(&pdev->dev, "failed to get mux gpio\n");
rc = PTR_ERR(gpio); goto err_free;
}
master->gpio_mux = gpio;
/* Grab the reserved memory region (use DMA API instead ?) */
rc = of_reserved_mem_region_to_resource(mnode, 0, &res); if (rc) {
dev_err(&pdev->dev, "Couldn't address to resource for reserved memory\n");
rc = -ENOMEM; goto err_free;
}
master->cf_mem_size = resource_size(&res);
master->cf_mem_addr = (uint32_t)res.start;
cf_mem_align = master->is_ast2500 ? 0x00100000 : 0x00200000; if (master->cf_mem_addr & (cf_mem_align - 1)) {
dev_err(&pdev->dev, "Reserved memory has insufficient alignment\n");
rc = -ENOMEM; goto err_free;
}
master->cf_mem = devm_ioremap_resource(&pdev->dev, &res); if (IS_ERR(master->cf_mem)) {
rc = PTR_ERR(master->cf_mem); goto err_free;
}
dev_dbg(&pdev->dev, "DRAM allocation @%x\n", master->cf_mem_addr);
/* AST2500 has a SW interrupt to the coprocessor */ if (master->is_ast2500) { /* Grab the CVIC (ColdFire interrupts controller) */
np = of_parse_phandle(mnode, "aspeed,cvic", 0); if (!np) {
dev_err(&pdev->dev, "Didn't find CVIC\n");
rc = -EINVAL; goto err_free;
}
master->cvic = devm_of_iomap(&pdev->dev, np, 0, NULL); if (IS_ERR(master->cvic)) {
of_node_put(np);
rc = PTR_ERR(master->cvic);
dev_err(&pdev->dev, "Error %d mapping CVIC\n", rc); goto err_free;
}
rc = of_property_read_u32(np, "copro-sw-interrupts",
&master->cvic_sw_irq);
of_node_put(np); if (rc) {
dev_err(&pdev->dev, "Can't find coprocessor SW interrupt\n"); goto err_free;
}
}
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.