Signed-off-by: Bernhard Nortmann <bernhard.nortm...@web.de> Squashed commit of the following:
commit 95f3614357446c4a35ec541bb2c21503c54d3fac Author: Bernhard Nortmann <bernhard.nortm...@web.de> Date: Fri Apr 8 09:10:17 2016 +0200 fel: Add support for multiple sequential readl/writel There are cases where "long" reads/writes might be used to transfer multiple values from/to sequential addresses. When doing so, we can avoid having to setup and upload the entire scratch buffer (ARM code) every time, by making the underlying functions auto-increment the address on each invocation. The patch implements this functionality, and maps the existing aw_fel_readl() and aw_fel_writel() to special cases (count == 1). Signed-off-by: Bernhard Nortmann <bernhard.nortm...@web.de> commit 20ececdfc7f3c4070469a7b74ba77bb74e01f876 Author: Bernhard Nortmann <bernhard.nortm...@web.de> Date: Fri Apr 8 09:00:20 2016 +0200 fel: Modify handling of command line args for "readl"/"writel" Most other commands use their decoded argument values directly, without storing them to local vars first. Also "writel" needs an (argc > 3). Signed-off-by: Bernhard Nortmann <bernhard.nortm...@web.de> commit b4216371b97e9f1dd19f7fc2ce720b9cb8e2434e Author: Siarhei Siamashka <siarhei.siamas...@gmail.com> Date: Sat Dec 19 08:22:26 2015 +0200 fel: Add "readl" and "writel" commands The read/write operations done by FEL are not suitable for accessing hardware registers. For example, trying to read a SID value using the "read" or "hexdump" commands results in the following: $ sunxi-fel hexdump 0x01c23800 4 01c23800: 87 00 00 00 __ __ __ __ __ __ __ __ __ __ __ __ Apparently, FEL tries to read data one byte at a time and this does not always work correctly. Introducing new commands to explicitly do 32-bit reads and writes helps: $ sunxi-fel readl 0x01c23800 0x16254187 Signed-off-by: Siarhei Siamashka <siarhei.siamas...@gmail.com> Tested-by: Bernhard Nortmann <bernhard.nortm...@web.de> --- fel.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/fel.c b/fel.c index ad0c866..e3a327a 100644 --- a/fel.c +++ b/fel.c @@ -655,6 +655,80 @@ void aw_write_arm_cp_reg(libusb_device_handle *usb, soc_sram_info *sram_info, aw_fel_execute(usb, sram_info->scratch_addr); } +/* multiple "readl" from sequential addresses to a destination buffer */ +void aw_fel_readl_n(libusb_device_handle *usb, uint32_t addr, + uint32_t *dst, size_t count) +{ + soc_sram_info *sram_info = aw_fel_get_sram_info(usb); + uint32_t val; + uint32_t arm_code[] = { + htole32(0xe59f0010), /* ldr r0, [pc, #16] */ + htole32(0xe5901000), /* ldr r1, [r0] */ + htole32(0xe58f100c), /* str r1, [pc, #12] */ + htole32(0xe2800004), /* add r0, r0, #4 */ + htole32(0xe58f0000), /* str r0, [pc] */ + htole32(0xe12fff1e), /* bx lr */ + htole32(addr), + /* value goes here */ + }; + /* scratch buffer setup: transfers ARM code and also sets the addr */ + aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code)); + while (count-- > 0) { + /* + * Since the scratch code auto-increments addr, we can simply + * execute it repeatedly for sequential "readl"s; retrieving + * one uint32_t each time. + */ + aw_fel_execute(usb, sram_info->scratch_addr); + aw_fel_read(usb, sram_info->scratch_addr + 28, &val, sizeof(val)); + *dst++ = le32toh(val); + } +} + +/* "readl" of a single value */ +uint32_t aw_fel_readl(libusb_device_handle *usb, uint32_t addr) +{ + uint32_t val; + aw_fel_readl_n(usb, addr, &val, 1); + return val; +} + +/* multiple "writel" from a source buffer to sequential addresses */ +void aw_fel_writel_n(libusb_device_handle *usb, uint32_t addr, + uint32_t *src, size_t count) +{ + if (count == 0) return; /* on zero count, do not access *src at all */ + + soc_sram_info *sram_info = aw_fel_get_sram_info(usb); + uint32_t arm_code[] = { + htole32(0xe59f0010), /* ldr r0, [pc, #16] */ + htole32(0xe59f1010), /* ldr r1, [pc, #16] */ + htole32(0xe5801000), /* str r1, [r0] */ + htole32(0xe2800004), /* add r0, r0, #4 */ + htole32(0xe58f0000), /* str r0, [pc] */ + htole32(0xe12fff1e), /* bx lr */ + htole32(addr), + htole32(*src++) + }; + /* scratch buffer setup: transfers ARM code, addr and first value */ + aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code)); + aw_fel_execute(usb, sram_info->scratch_addr); /* stores first value */ + while (--count > 0) { + /* + * Subsequent transfers only need to set up the next value + * to store (since the scratch code auto-increments addr). + */ + aw_fel_write(usb, src++, sram_info->scratch_addr + 28, sizeof(uint32_t)); + aw_fel_execute(usb, sram_info->scratch_addr); + } +} + +/* "writel" of a single value */ +void aw_fel_writel(libusb_device_handle *usb, uint32_t addr, uint32_t val) +{ + aw_fel_writel_n(usb, addr, &val, 1); +} + void aw_enable_l2_cache(libusb_device_handle *usb, soc_sram_info *sram_info) { uint32_t arm_code[] = { @@ -1386,6 +1460,8 @@ int main(int argc, char **argv) " hex[dump] address length Dumps memory region in hex\n" " dump address length Binary memory dump\n" " exe[cute] address Call function address\n" + " readl address Read 32-bit value from device memory\n" + " writel address value Write 32-bit value to device memory\n" " read address length file Write memory contents into file\n" " write address file Store file contents into memory\n" " write-with-progress addr file \"write\" with progress bar\n" @@ -1458,6 +1534,12 @@ int main(int argc, char **argv) } else if (strncmp(argv[1], "dump", 4) == 0 && argc > 3) { aw_fel_dump(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0)); skip = 3; + } else if (strcmp(argv[1], "readl") == 0 && argc > 2) { + printf("0x%08x\n", aw_fel_readl(handle, strtoul(argv[2], NULL, 0))); + skip = 2; + } else if (strcmp(argv[1], "writel") == 0 && argc > 3) { + aw_fel_writel(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0)); + skip = 3; } else if (strncmp(argv[1], "exe", 3) == 0 && argc > 2) { aw_fel_execute(handle, strtoul(argv[2], NULL, 0)); skip=3; -- 2.4.10 -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.