Hello again,
Having looked at the l4vbus_gpio functions and struggled with providing
suitable devices, I decided to take the simpler approach and just ask for the
I/O memory of the devices and access that directly. However, this didn't prove
as straightforward as anticipated, either.
The aim was to take the previously-mentioned device resources of the following
form and to perform l4io_request_iomem (or l4io_request_resource_iomem) to get
addresses of virtual regions corresponding to the different physical memory
regions.
PORTA = Hw.Device(function()
Property.hid = "jz4780-gpio-PORTA";
Resource.regs = Res.mmio(0x10010000, 0x100100ff);
...
end);
PORTB = Hw.Device(function()
Property.hid = "jz4780-gpio-PORTB";
Resource.regs = Res.mmio(0x10010100, 0x100101ff);
...
end);
...
PORTF = Hw.Device(function()
Property.hid = "jz4780-gpio-PORTF";
Resource.regs = Res.mmio(0x10010500, 0x100105ff);
...
end);
It was indeed possible to obtain the resources involved with individual ports
and also to obtain an address for each port region. However, accesses relative
to these base addresses did not produce the expected results (LED output
changes, switch input changes).
(Looking at the virtual and physical regions in jdb suggested that the
accesses were not being propagated, although I was also not successful in
putting values into physical memory addresses and obtaining any of the
expected results, either.)
Now, I did wonder how such a small, 256-byte region mapping would actually
work with my hardware. The JZ4780 does not support pages smaller than 4K when
mapping memory, but I did notice that I do get an exception if trying to
access beyond the end of the virtual region.
(I found this out when considering that perhaps the virtual address might
actually point to the base of the hardware page containing the region. So, I
added a region offset to the base and tried to perform a memory access.
Obviously, returning the hardware page address would be an unfortunate choice
because it would oblige the API user to know about such things. Clearly, the
API should return the address of the actual region, and maybe it does.)
So, if this smaller-than-hardware page size is enforced, there must be a
mechanism above the plain TLB mechanism that performs such enforcement. One
interesting thing I noticed was that when requesting two different regions,
the virtual addresses for the base of the regions were 4K apart, not 256 bytes
apart. In any case, I was left wondering if any such mechanism might be
preventing accesses from being correctly propagated.
To simplify things a bit more, I then decided to just define the entire GPIO
region in the device tree:
GPIO = Hw.Device(function()
Property.hid = "JZ4780 GPIO";
Resource.regs = Res.mmio(0x10010000, 0x100105ff);
end);
Requesting the memory for this device succeeds as before, but then performing
accesses relative to the returned virtual address (with port F at vaddr +
0x500, for instance) also succeeds and produces the desired result, unlike
before.
So, what is this mechanism that handles accesses to regions that do not
correspond to hardware pages (either in size or alignment)? Is there some kind
of address-based trapping that redirects accesses to some kind of privately-
allocated page that is then mapped to the hardware page concerned? Is it
possible that this mechanism does not work on MIPS or on my specific device?
I apologise if I should be answering my own questions by looking at the code
or particular documentation resources.
Paul