diff mbox series

[v4,6/7] hw/sd/sdhci: Implement Freescale eSDHC device model

Message ID 20221018210146.193159-7-shentey@gmail.com
State Handled Elsewhere
Headers show
Series ppc/e500: Add support for two types of flash, cleanup | expand

Commit Message

Bernhard Beschow Oct. 18, 2022, 9:01 p.m. UTC
Will allow e500 boards to access SD cards using just their own devices.

Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
 hw/sd/sdhci.c         | 120 +++++++++++++++++++++++++++++++++++++++++-
 include/hw/sd/sdhci.h |   3 ++
 2 files changed, 122 insertions(+), 1 deletion(-)

Comments

Philippe Mathieu-Daudé Oct. 27, 2022, 9:40 p.m. UTC | #1
Hi Bernhard,

On 18/10/22 23:01, Bernhard Beschow wrote:
> Will allow e500 boards to access SD cards using just their own devices.
> 
> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
> ---
>   hw/sd/sdhci.c         | 120 +++++++++++++++++++++++++++++++++++++++++-
>   include/hw/sd/sdhci.h |   3 ++
>   2 files changed, 122 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
> index 306070c872..8d8ad9ff24 100644
> --- a/hw/sd/sdhci.c
> +++ b/hw/sd/sdhci.c
> @@ -1369,6 +1369,7 @@ void sdhci_initfn(SDHCIState *s)
>       s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
>   
>       s->io_ops = &sdhci_mmio_ops;
> +    s->io_registers_map_size = SDHC_REGISTERS_MAP_SIZE;
>   }
>   
>   void sdhci_uninitfn(SDHCIState *s)
> @@ -1392,7 +1393,7 @@ void sdhci_common_realize(SDHCIState *s, Error **errp)
>       s->fifo_buffer = g_malloc0(s->buf_maxsz);
>   
>       memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci",
> -                          SDHC_REGISTERS_MAP_SIZE);
> +                          s->io_registers_map_size);

I don't think we want to change this region size. [see below]

>   void sdhci_common_unrealize(SDHCIState *s)
> @@ -1575,6 +1576,122 @@ static const TypeInfo sdhci_bus_info = {
>       .class_init = sdhci_bus_class_init,
>   };
>   
> +/* --- qdev Freescale eSDHC --- */
> +
> +/* Watermark Level Register */
> +#define ESDHC_WML                    0x44
> +
> +/* Control Register for DMA transfer */
> +#define ESDHC_DMA_SYSCTL            0x40c
> +
> +#define ESDHC_REGISTERS_MAP_SIZE    0x410

My preferred approach would be to create a container region with a
size of ESDHC_REGISTERS_MAP_SIZE. Map the SDHC_REGISTERS_MAP region
in the container at offset 0, priority -1. Add 2 register regions
for ESDHC_WML and ESDHC_DMA_SYSCTL, and map them with priority 1 in
the container. ...

> +static uint64_t esdhci_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    uint64_t ret;
> +
> +    switch (offset) {
> +    case SDHC_SYSAD:
> +    case SDHC_BLKSIZE:
> +    case SDHC_ARGUMENT:
> +    case SDHC_TRNMOD:
> +    case SDHC_RSPREG0:
> +    case SDHC_RSPREG1:
> +    case SDHC_RSPREG2:
> +    case SDHC_RSPREG3:
> +    case SDHC_BDATA:
> +    case SDHC_PRNSTS:
> +    case SDHC_HOSTCTL:
> +    case SDHC_CLKCON:
> +    case SDHC_NORINTSTS:
> +    case SDHC_NORINTSTSEN:
> +    case SDHC_NORINTSIGEN:
> +    case SDHC_ACMD12ERRSTS:
> +    case SDHC_CAPAB:
> +    case SDHC_SLOT_INT_STATUS:
> +        ret = sdhci_read(opaque, offset, size);
> +        break;

... Then you don't need these cases.

> +    case ESDHC_WML:
> +    case ESDHC_DMA_SYSCTL:
> +        ret = 0;
> +        qemu_log_mask(LOG_UNIMP, "ESDHC rd @0x%02" HWADDR_PRIx
> +                      " not implemented\n", offset);

But then I realize you only treat these 2 registers as UNIMP.

So now, I'd create 1 UNIMP region for ESDHC_WML and map it
into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
another UNIMP region of ESDHC_REGISTERS_MAP_SIZE - 
SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
hw/arm/bcm2835_peripherals.c.

But the ESDHC_WML register has address 0x44 and fits inside the
SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
upper part of the SDHC_CAPAB register. These bits are undefined
on the spec v2, which I see you are setting in esdhci_init().
So this register should already return 0, otherwise we have
a bug. Thus we don't need to handle this ESDHC_WML particularly.

And your model is reduced to handling create_unimp() in esdhci_realize().

Am I missing something?

Regards,

Phil.
Bernhard Beschow Oct. 29, 2022, 11:33 a.m. UTC | #2
Am 27. Oktober 2022 21:40:01 UTC schrieb "Philippe Mathieu-Daudé" <philmd@linaro.org>:
>Hi Bernhard,
>
>On 18/10/22 23:01, Bernhard Beschow wrote:
>> Will allow e500 boards to access SD cards using just their own devices.
>> 
>> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>> ---
>>   hw/sd/sdhci.c         | 120 +++++++++++++++++++++++++++++++++++++++++-
>>   include/hw/sd/sdhci.h |   3 ++
>>   2 files changed, 122 insertions(+), 1 deletion(-)
>> 
>> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
>> index 306070c872..8d8ad9ff24 100644
>> --- a/hw/sd/sdhci.c
>> +++ b/hw/sd/sdhci.c
>> @@ -1369,6 +1369,7 @@ void sdhci_initfn(SDHCIState *s)
>>       s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
>>         s->io_ops = &sdhci_mmio_ops;
>> +    s->io_registers_map_size = SDHC_REGISTERS_MAP_SIZE;
>>   }
>>     void sdhci_uninitfn(SDHCIState *s)
>> @@ -1392,7 +1393,7 @@ void sdhci_common_realize(SDHCIState *s, Error **errp)
>>       s->fifo_buffer = g_malloc0(s->buf_maxsz);
>>         memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci",
>> -                          SDHC_REGISTERS_MAP_SIZE);
>> +                          s->io_registers_map_size);
>
>I don't think we want to change this region size. [see below]
>
>>   void sdhci_common_unrealize(SDHCIState *s)
>> @@ -1575,6 +1576,122 @@ static const TypeInfo sdhci_bus_info = {
>>       .class_init = sdhci_bus_class_init,
>>   };
>>   +/* --- qdev Freescale eSDHC --- */
>> +
>> +/* Watermark Level Register */
>> +#define ESDHC_WML                    0x44
>> +
>> +/* Control Register for DMA transfer */
>> +#define ESDHC_DMA_SYSCTL            0x40c
>> +
>> +#define ESDHC_REGISTERS_MAP_SIZE    0x410
>
>My preferred approach would be to create a container region with a
>size of ESDHC_REGISTERS_MAP_SIZE. Map the SDHC_REGISTERS_MAP region
>in the container at offset 0, priority -1. Add 2 register regions
>for ESDHC_WML and ESDHC_DMA_SYSCTL, and map them with priority 1 in
>the container. ...
>
>> +static uint64_t esdhci_read(void *opaque, hwaddr offset, unsigned size)
>> +{
>> +    uint64_t ret;
>> +
>> +    switch (offset) {
>> +    case SDHC_SYSAD:
>> +    case SDHC_BLKSIZE:
>> +    case SDHC_ARGUMENT:
>> +    case SDHC_TRNMOD:
>> +    case SDHC_RSPREG0:
>> +    case SDHC_RSPREG1:
>> +    case SDHC_RSPREG2:
>> +    case SDHC_RSPREG3:
>> +    case SDHC_BDATA:
>> +    case SDHC_PRNSTS:
>> +    case SDHC_HOSTCTL:
>> +    case SDHC_CLKCON:
>> +    case SDHC_NORINTSTS:
>> +    case SDHC_NORINTSTSEN:
>> +    case SDHC_NORINTSIGEN:
>> +    case SDHC_ACMD12ERRSTS:
>> +    case SDHC_CAPAB:
>> +    case SDHC_SLOT_INT_STATUS:
>> +        ret = sdhci_read(opaque, offset, size);
>> +        break;
>
>... Then you don't need these cases.
>
>> +    case ESDHC_WML:
>> +    case ESDHC_DMA_SYSCTL:
>> +        ret = 0;
>> +        qemu_log_mask(LOG_UNIMP, "ESDHC rd @0x%02" HWADDR_PRIx
>> +                      " not implemented\n", offset);
>
>But then I realize you only treat these 2 registers as UNIMP.
>
>So now, I'd create 1 UNIMP region for ESDHC_WML and map it
>into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
>another UNIMP region of ESDHC_REGISTERS_MAP_SIZE - SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
>0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
>hw/arm/bcm2835_peripherals.c.
>
>But the ESDHC_WML register has address 0x44 and fits inside the
>SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
>upper part of the SDHC_CAPAB register. These bits are undefined
>on the spec v2, which I see you are setting in esdhci_init().
>So this register should already return 0, otherwise we have
>a bug. Thus we don't need to handle this ESDHC_WML particularly.
>
>And your model is reduced to handling create_unimp() in esdhci_realize().
>
>Am I missing something?

The mmio ops are big endian and need to be aligned to a 4-byte boundary. It took me quite a while to debug this. So shall I just create an additional memory region for the region above SDHC_REGISTERS_MAP_SIZE for ESDHC_DMA_SYSCTL?

Best regards,
Bernhard
>
>Regards,
>
>Phil.
Bernhard Beschow Oct. 29, 2022, 1:04 p.m. UTC | #3
Am 29. Oktober 2022 11:33:51 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>Am 27. Oktober 2022 21:40:01 UTC schrieb "Philippe Mathieu-Daudé" <philmd@linaro.org>:
>>Hi Bernhard,
>>
>>On 18/10/22 23:01, Bernhard Beschow wrote:
>>> Will allow e500 boards to access SD cards using just their own devices.
>>> 
>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>>> ---
>>>   hw/sd/sdhci.c         | 120 +++++++++++++++++++++++++++++++++++++++++-
>>>   include/hw/sd/sdhci.h |   3 ++
>>>   2 files changed, 122 insertions(+), 1 deletion(-)
>>> 
>>> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
>>> index 306070c872..8d8ad9ff24 100644
>>> --- a/hw/sd/sdhci.c
>>> +++ b/hw/sd/sdhci.c
>>> @@ -1369,6 +1369,7 @@ void sdhci_initfn(SDHCIState *s)
>>>       s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
>>>         s->io_ops = &sdhci_mmio_ops;
>>> +    s->io_registers_map_size = SDHC_REGISTERS_MAP_SIZE;
>>>   }
>>>     void sdhci_uninitfn(SDHCIState *s)
>>> @@ -1392,7 +1393,7 @@ void sdhci_common_realize(SDHCIState *s, Error **errp)
>>>       s->fifo_buffer = g_malloc0(s->buf_maxsz);
>>>         memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci",
>>> -                          SDHC_REGISTERS_MAP_SIZE);
>>> +                          s->io_registers_map_size);
>>
>>I don't think we want to change this region size. [see below]
>>
>>>   void sdhci_common_unrealize(SDHCIState *s)
>>> @@ -1575,6 +1576,122 @@ static const TypeInfo sdhci_bus_info = {
>>>       .class_init = sdhci_bus_class_init,
>>>   };
>>>   +/* --- qdev Freescale eSDHC --- */
>>> +
>>> +/* Watermark Level Register */
>>> +#define ESDHC_WML                    0x44
>>> +
>>> +/* Control Register for DMA transfer */
>>> +#define ESDHC_DMA_SYSCTL            0x40c
>>> +
>>> +#define ESDHC_REGISTERS_MAP_SIZE    0x410
>>
>>My preferred approach would be to create a container region with a
>>size of ESDHC_REGISTERS_MAP_SIZE. Map the SDHC_REGISTERS_MAP region
>>in the container at offset 0, priority -1. Add 2 register regions
>>for ESDHC_WML and ESDHC_DMA_SYSCTL, and map them with priority 1 in
>>the container. ...
>>
>>> +static uint64_t esdhci_read(void *opaque, hwaddr offset, unsigned size)
>>> +{
>>> +    uint64_t ret;
>>> +
>>> +    switch (offset) {
>>> +    case SDHC_SYSAD:
>>> +    case SDHC_BLKSIZE:
>>> +    case SDHC_ARGUMENT:
>>> +    case SDHC_TRNMOD:
>>> +    case SDHC_RSPREG0:
>>> +    case SDHC_RSPREG1:
>>> +    case SDHC_RSPREG2:
>>> +    case SDHC_RSPREG3:
>>> +    case SDHC_BDATA:
>>> +    case SDHC_PRNSTS:
>>> +    case SDHC_HOSTCTL:
>>> +    case SDHC_CLKCON:
>>> +    case SDHC_NORINTSTS:
>>> +    case SDHC_NORINTSTSEN:
>>> +    case SDHC_NORINTSIGEN:
>>> +    case SDHC_ACMD12ERRSTS:
>>> +    case SDHC_CAPAB:
>>> +    case SDHC_SLOT_INT_STATUS:
>>> +        ret = sdhci_read(opaque, offset, size);
>>> +        break;
>>
>>... Then you don't need these cases.
>>
>>> +    case ESDHC_WML:
>>> +    case ESDHC_DMA_SYSCTL:
>>> +        ret = 0;
>>> +        qemu_log_mask(LOG_UNIMP, "ESDHC rd @0x%02" HWADDR_PRIx
>>> +                      " not implemented\n", offset);
>>
>>But then I realize you only treat these 2 registers as UNIMP.
>>
>>So now, I'd create 1 UNIMP region for ESDHC_WML and map it
>>into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
>>another UNIMP region of ESDHC_REGISTERS_MAP_SIZE - SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
>>0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
>>hw/arm/bcm2835_peripherals.c.
>>
>>But the ESDHC_WML register has address 0x44 and fits inside the
>>SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
>>upper part of the SDHC_CAPAB register. These bits are undefined
>>on the spec v2, which I see you are setting in esdhci_init().
>>So this register should already return 0, otherwise we have
>>a bug. Thus we don't need to handle this ESDHC_WML particularly.

My idea here was to catch this unimplemented case in order to indicate this clearly to users. Perhaps it nudges somebody to provide a patch?

>>
>>And your model is reduced to handling create_unimp() in esdhci_realize().
>>
>>Am I missing something?
>
>The mmio ops are big endian and need to be aligned to a 4-byte boundary. It took me quite a while to debug this. So shall I just create an additional memory region for the region above SDHC_REGISTERS_MAP_SIZE for ESDHC_DMA_SYSCTL?

All in all I currently don't have a better idea than keeping the custom i/o ops for the standard region and adding an additional unimplemented region for ESDHC_DMA_SYSCTL. I think I'd have to dynamically allocate memory for it where I still need to figure out how not to leak it.

Best regards,
Bernhard
>
>Best regards,
>Bernhard
>>
>>Regards,
>>
>>Phil.
>
Bernhard Beschow Oct. 29, 2022, 6:28 p.m. UTC | #4
Am 29. Oktober 2022 13:04:00 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>Am 29. Oktober 2022 11:33:51 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>Am 27. Oktober 2022 21:40:01 UTC schrieb "Philippe Mathieu-Daudé" <philmd@linaro.org>:
>>>Hi Bernhard,
>>>
>>>On 18/10/22 23:01, Bernhard Beschow wrote:
>>>> Will allow e500 boards to access SD cards using just their own devices.
>>>> 
>>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>>>> ---
>>>>   hw/sd/sdhci.c         | 120 +++++++++++++++++++++++++++++++++++++++++-
>>>>   include/hw/sd/sdhci.h |   3 ++
>>>>   2 files changed, 122 insertions(+), 1 deletion(-)
>>>> 
>>>> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
>>>> index 306070c872..8d8ad9ff24 100644
>>>> --- a/hw/sd/sdhci.c
>>>> +++ b/hw/sd/sdhci.c
>>>> @@ -1369,6 +1369,7 @@ void sdhci_initfn(SDHCIState *s)
>>>>       s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
>>>>         s->io_ops = &sdhci_mmio_ops;
>>>> +    s->io_registers_map_size = SDHC_REGISTERS_MAP_SIZE;
>>>>   }
>>>>     void sdhci_uninitfn(SDHCIState *s)
>>>> @@ -1392,7 +1393,7 @@ void sdhci_common_realize(SDHCIState *s, Error **errp)
>>>>       s->fifo_buffer = g_malloc0(s->buf_maxsz);
>>>>         memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci",
>>>> -                          SDHC_REGISTERS_MAP_SIZE);
>>>> +                          s->io_registers_map_size);
>>>
>>>I don't think we want to change this region size. [see below]
>>>
>>>>   void sdhci_common_unrealize(SDHCIState *s)
>>>> @@ -1575,6 +1576,122 @@ static const TypeInfo sdhci_bus_info = {
>>>>       .class_init = sdhci_bus_class_init,
>>>>   };
>>>>   +/* --- qdev Freescale eSDHC --- */
>>>> +
>>>> +/* Watermark Level Register */
>>>> +#define ESDHC_WML                    0x44
>>>> +
>>>> +/* Control Register for DMA transfer */
>>>> +#define ESDHC_DMA_SYSCTL            0x40c
>>>> +
>>>> +#define ESDHC_REGISTERS_MAP_SIZE    0x410
>>>
>>>My preferred approach would be to create a container region with a
>>>size of ESDHC_REGISTERS_MAP_SIZE. Map the SDHC_REGISTERS_MAP region
>>>in the container at offset 0, priority -1. Add 2 register regions
>>>for ESDHC_WML and ESDHC_DMA_SYSCTL, and map them with priority 1 in
>>>the container. ...
>>>
>>>> +static uint64_t esdhci_read(void *opaque, hwaddr offset, unsigned size)
>>>> +{
>>>> +    uint64_t ret;
>>>> +
>>>> +    switch (offset) {
>>>> +    case SDHC_SYSAD:
>>>> +    case SDHC_BLKSIZE:
>>>> +    case SDHC_ARGUMENT:
>>>> +    case SDHC_TRNMOD:
>>>> +    case SDHC_RSPREG0:
>>>> +    case SDHC_RSPREG1:
>>>> +    case SDHC_RSPREG2:
>>>> +    case SDHC_RSPREG3:
>>>> +    case SDHC_BDATA:
>>>> +    case SDHC_PRNSTS:
>>>> +    case SDHC_HOSTCTL:
>>>> +    case SDHC_CLKCON:
>>>> +    case SDHC_NORINTSTS:
>>>> +    case SDHC_NORINTSTSEN:
>>>> +    case SDHC_NORINTSIGEN:
>>>> +    case SDHC_ACMD12ERRSTS:
>>>> +    case SDHC_CAPAB:
>>>> +    case SDHC_SLOT_INT_STATUS:
>>>> +        ret = sdhci_read(opaque, offset, size);
>>>> +        break;
>>>
>>>... Then you don't need these cases.
>>>
>>>> +    case ESDHC_WML:
>>>> +    case ESDHC_DMA_SYSCTL:
>>>> +        ret = 0;
>>>> +        qemu_log_mask(LOG_UNIMP, "ESDHC rd @0x%02" HWADDR_PRIx
>>>> +                      " not implemented\n", offset);
>>>
>>>But then I realize you only treat these 2 registers as UNIMP.
>>>
>>>So now, I'd create 1 UNIMP region for ESDHC_WML and map it
>>>into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
>>>another UNIMP region of ESDHC_REGISTERS_MAP_SIZE - SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
>>>0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
>>>hw/arm/bcm2835_peripherals.c.
>>>
>>>But the ESDHC_WML register has address 0x44 and fits inside the
>>>SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
>>>upper part of the SDHC_CAPAB register. These bits are undefined
>>>on the spec v2, which I see you are setting in esdhci_init().
>>>So this register should already return 0, otherwise we have
>>>a bug. Thus we don't need to handle this ESDHC_WML particularly.
>
>My idea here was to catch this unimplemented case in order to indicate this clearly to users. Perhaps it nudges somebody to provide a patch?
>
>>>
>>>And your model is reduced to handling create_unimp() in esdhci_realize().
>>>
>>>Am I missing something?
>>
>>The mmio ops are big endian and need to be aligned to a 4-byte boundary. It took me quite a while to debug this. So shall I just create an additional memory region for the region above SDHC_REGISTERS_MAP_SIZE for ESDHC_DMA_SYSCTL?
>
>All in all I currently don't have a better idea than keeping the custom i/o ops for the standard region and adding an additional unimplemented region for ESDHC_DMA_SYSCTL. I think I'd have to dynamically allocate memory for it where I still need to figure out how not to leak it.

By simply reusing sdhci_{read,write} in eSDHC's io_ops struct I was able to remove the custom implementations while having big endian and the alignments proper. However, I don't see a way of adding two memory regions - with or without a container. With a container I'd have to somehow preserve the mmio attribute which is initialized by the parent class, re-initialize it with the container, and add the preserved memory region as child. This seems very fragile, esp. since the parent class has created an alias for mmio in sysbus. Without a container, one would have two memory regions that both have to be mapped separately by the caller, i.e. it burdens the caller with an implementation detail.

Any suggestions?

Best regards,
Bernhard
>
>Best regards,
>Bernhard
>>
>>Best regards,
>>Bernhard
>>>
>>>Regards,
>>>
>>>Phil.
>>
>
Philippe Mathieu-Daudé Oct. 29, 2022, 11:10 p.m. UTC | #5
On 29/10/22 20:28, Bernhard Beschow wrote:
> Am 29. Oktober 2022 13:04:00 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>> Am 29. Oktober 2022 11:33:51 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>> Am 27. Oktober 2022 21:40:01 UTC schrieb "Philippe Mathieu-Daudé" <philmd@linaro.org>:
>>>> Hi Bernhard,
>>>>
>>>> On 18/10/22 23:01, Bernhard Beschow wrote:
>>>>> Will allow e500 boards to access SD cards using just their own devices.
>>>>>
>>>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>>>>> ---
>>>>>    hw/sd/sdhci.c         | 120 +++++++++++++++++++++++++++++++++++++++++-
>>>>>    include/hw/sd/sdhci.h |   3 ++
>>>>>    2 files changed, 122 insertions(+), 1 deletion(-)

>>>> So now, I'd create 1 UNIMP region for ESDHC_WML and map it
>>>> into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
>>>> another UNIMP region of ESDHC_REGISTERS_MAP_SIZE - SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
>>>> 0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
>>>> hw/arm/bcm2835_peripherals.c.
>>>>
>>>> But the ESDHC_WML register has address 0x44 and fits inside the
>>>> SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
>>>> upper part of the SDHC_CAPAB register. These bits are undefined
>>>> on the spec v2, which I see you are setting in esdhci_init().
>>>> So this register should already return 0, otherwise we have
>>>> a bug. Thus we don't need to handle this ESDHC_WML particularly.
>>
>> My idea here was to catch this unimplemented case in order to indicate this clearly to users. Perhaps it nudges somebody to provide a patch?
>>
>>>>
>>>> And your model is reduced to handling create_unimp() in esdhci_realize().
>>>>
>>>> Am I missing something?
>>>
>>> The mmio ops are big endian and need to be aligned to a 4-byte boundary. It took me quite a while to debug this. So shall I just create an additional memory region for the region above SDHC_REGISTERS_MAP_SIZE for ESDHC_DMA_SYSCTL?
>>
>> All in all I currently don't have a better idea than keeping the custom i/o ops for the standard region and adding an additional unimplemented region for ESDHC_DMA_SYSCTL. I think I'd have to dynamically allocate memory for it where I still need to figure out how not to leak it.
> 
> By simply reusing sdhci_{read,write} in eSDHC's io_ops struct I was able to remove the custom implementations while having big endian and the alignments proper. However, I don't see a way of adding two memory regions - with or without a container. With a container I'd have to somehow preserve the mmio attribute which is initialized by the parent class, re-initialize it with the container, and add the preserved memory region as child. This seems very fragile, esp. since the parent class has created an alias for mmio in sysbus. Without a container, one would have two memory regions that both have to be mapped separately by the caller, i.e. it burdens the caller with an implementation detail.
> 
> Any suggestions?

Can you share branch and how to test?
Bernhard Beschow Oct. 30, 2022, 11:46 a.m. UTC | #6
On Sun, Oct 30, 2022 at 1:10 AM Philippe Mathieu-Daudé <philmd@linaro.org>
wrote:

> On 29/10/22 20:28, Bernhard Beschow wrote:
> > Am 29. Oktober 2022 13:04:00 UTC schrieb Bernhard Beschow <
> shentey@gmail.com>:
> >> Am 29. Oktober 2022 11:33:51 UTC schrieb Bernhard Beschow <
> shentey@gmail.com>:
> >>> Am 27. Oktober 2022 21:40:01 UTC schrieb "Philippe Mathieu-Daudé" <
> philmd@linaro.org>:
> >>>> Hi Bernhard,
> >>>>
> >>>> On 18/10/22 23:01, Bernhard Beschow wrote:
> >>>>> Will allow e500 boards to access SD cards using just their own
> devices.
> >>>>>
> >>>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
> >>>>> ---
> >>>>>    hw/sd/sdhci.c         | 120
> +++++++++++++++++++++++++++++++++++++++++-
> >>>>>    include/hw/sd/sdhci.h |   3 ++
> >>>>>    2 files changed, 122 insertions(+), 1 deletion(-)
>
> >>>> So now, I'd create 1 UNIMP region for ESDHC_WML and map it
> >>>> into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
> >>>> another UNIMP region of ESDHC_REGISTERS_MAP_SIZE -
> SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
> >>>> 0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
> >>>> hw/arm/bcm2835_peripherals.c.
> >>>>
> >>>> But the ESDHC_WML register has address 0x44 and fits inside the
> >>>> SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
> >>>> upper part of the SDHC_CAPAB register. These bits are undefined
> >>>> on the spec v2, which I see you are setting in esdhci_init().
> >>>> So this register should already return 0, otherwise we have
> >>>> a bug. Thus we don't need to handle this ESDHC_WML particularly.
> >>
> >> My idea here was to catch this unimplemented case in order to indicate
> this clearly to users. Perhaps it nudges somebody to provide a patch?
> >>
> >>>>
> >>>> And your model is reduced to handling create_unimp() in
> esdhci_realize().
> >>>>
> >>>> Am I missing something?
> >>>
> >>> The mmio ops are big endian and need to be aligned to a 4-byte
> boundary. It took me quite a while to debug this. So shall I just create an
> additional memory region for the region above SDHC_REGISTERS_MAP_SIZE for
> ESDHC_DMA_SYSCTL?
> >>
> >> All in all I currently don't have a better idea than keeping the custom
> i/o ops for the standard region and adding an additional unimplemented
> region for ESDHC_DMA_SYSCTL. I think I'd have to dynamically allocate
> memory for it where I still need to figure out how not to leak it.
> >
> > By simply reusing sdhci_{read,write} in eSDHC's io_ops struct I was able
> to remove the custom implementations while having big endian and the
> alignments proper. However, I don't see a way of adding two memory regions
> - with or without a container. With a container I'd have to somehow
> preserve the mmio attribute which is initialized by the parent class,
> re-initialize it with the container, and add the preserved memory region as
> child. This seems very fragile, esp. since the parent class has created an
> alias for mmio in sysbus. Without a container, one would have two memory
> regions that both have to be mapped separately by the caller, i.e. it
> burdens the caller with an implementation detail.
> >
> > Any suggestions?
>
> Can you share branch and how to test?
>

QEMU branch: https://github.com/shentok/qemu/tree/e500-flash

How to test:
1. `git clone -b e500 https://github.com/shentok/buildroot.git`
2. `cd buildroot`
3. `make qemu_ppc_e500mc_defconfig`
4. `make`
5. `cd output/images`
6. `dd if=/dev/zero of=root.img bs=1M count=64 && dd if=rootfs.ext2
of=root.img bs=1M conv=notrunc`
7. `qemu-system-ppc -M ppce500 -cpu e500mc -m 256 -kernel uImage -append
"console=ttyS0 rootwait root=/dev/mmcblk0" -device sd-card,drive=mydrive
-drive id=mydrive,if=none,file=root.img,format=raw`

Note that step 6 might be required every time before qemu-system-ppc is
started, otherwise this may cause an fsck. The output on the boot console
will look something along these lines (note that no errors are reported):

  Memory CAM mapping: 16/16/16/16/64/64/64 Mb, residual: 0Mb
  Activating Kernel Userspace Access Protection
  Activating Kernel Userspace Execution Prevention
  Linux version 5.17.7 (zcone-pisint@osoxes)
(powerpc-buildroot-linux-gnu-gcc.br_real (Buildroot
2022.08-655-gf8a0d1480a) 11.3.0, GNU ld (GNU Binutils) 2.38) #1 SMP Sat Oct
29 12:49:54 CEST 2022
  Using QEMU e500 machine description
  printk: bootconsole [udbg0] enabled
  CPU maps initialized for 1 thread per core
  -----------------------------------------------------
  phys_mem_size     = 0x10000000
  dcache_bsize      = 0x40
  icache_bsize      = 0x40
  cpu_features      = 0x0000000000000194
    possible        = 0x000000000001039c
    always          = 0x0000000000000100
  cpu_user_features = 0x8c008000 0x08000000
  mmu_features      = 0x000a0010
  -----------------------------------------------------
  qemu_e500_setup_arch()
  barrier-nospec: using isync; sync as speculation barrier
  Zone ranges:
    Normal   [mem 0x0000000000000000-0x000000000fffffff]
    HighMem  empty
  Movable zone start for each node
  Early memory node ranges
    node   0: [mem 0x0000000000000000-0x000000000fffffff]
  Initmem setup node 0 [mem 0x0000000000000000-0x000000000fffffff]
  MMU: Allocated 1088 bytes of context maps for 255 contexts
  percpu: Embedded 16 pages/cpu s33804 r8192 d23540 u65536
  Built 1 zonelists, mobility grouping on.  Total pages: 65024
  Kernel command line: console=ttyS0 rootwait root=/dev/mmcblk0 nokaslr
  Unknown kernel command line parameters "nokaslr", will be passed to user
space.
  Dentry cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
  Inode-cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
  mem auto-init: stack:off, heap alloc:off, heap free:off
  Kernel virtual memory layout:
    * 0xffa5f000..0xfffff000  : fixmap
    * 0xff800000..0xffa00000  : highmem PTEs
    * 0xd1000000..0xff800000  : vmalloc & ioremap
  Memory: 174608K/262144K available (12680K kernel code, 1080K rwdata,
3552K rodata, 396K init, 238K bss, 87536K reserved, 0K cma-reserved, 0K
highmem)
  SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
  rcu: Hierarchical RCU implementation.
  rcu: RCU event tracing is enabled.
  rcu: RCU restricting CPUs from NR_CPUS=24 to nr_cpu_ids=1.
  rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
  rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
  NR_IRQS: 512, nr_irqs: 512, preallocated irqs: 16
  mpic: Setting up MPIC " OpenPIC  " version 1.2 at fe0040000, max 1 CPUs
  mpic: ISU size: 256, shift: 8, mask: ff
  mpic: Initializing for 256 sources
  random: get_random_u32 called from start_kernel+0x524/0x6b0 with
crng_init=0
  clocksource: timebase: mask: 0xffffffffffffffff max_cycles: 0x5c4093a7d1,
max_idle_ns: 440795210635 ns
  clocksource: timebase mult[2800000] shift[24] registered
  Console: colour dummy device 80x25
  pid_max: default: 32768 minimum: 301
  Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
  Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
  e500 family performance monitor hardware support registered
  rcu: Hierarchical SRCU implementation.
  smp: Bringing up secondary CPUs ...
  smp: Brought up 1 node, 1 CPU
  devtmpfs: initialized
  clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff,
max_idle_ns: 7645041785100000 ns
  futex hash table entries: 256 (order: 2, 16384 bytes, linear)
  NET: Registered PF_NETLINK/PF_ROUTE protocol family
  audit: initializing netlink subsys (disabled)

  Found FSL PCI host bridge at 0x0000000fe0008000. Firmware bus number:
0->255
  PCI host bridge /pci@fe0008000 (primary) ranges:
   MEM 0x0000000c00000000..0x0000000c1fffffff -> 0x00000000e0000000
    IO 0x0000000fe1000000..0x0000000fe100ffff -> 0x0000000000000000
  /pci@fe0008000: PCICSRBAR @ 0xdff00000
  setup_pci_atmu: end of DRAM 10000000
  Machine: QEMU ppce500
  SoC family: QorIQ
  SoC ID: svr:0x00000000, Revision: 0.0
  audit: type=2000 audit(0.092:1): state=initialized audit_enabled=0 res=1
  fsl-pamu: fsl_pamu_init: could not find a PAMU node
  software IO TLB: tearing down default memory pool
  PCI: Probing PCI hardware
  fsl-pci fe0008000.pci: PCI host bridge to bus 8000:00
  pci_bus 8000:00: root bus resource [io  0x0000-0xffff]
  pci_bus 8000:00: root bus resource [mem 0xc00000000-0xc1fffffff] (bus
address [0xe0000000-0xffffffff])
  pci_bus 8000:00: root bus resource [bus 00-ff]
  pci_bus 8000:00: busn_res: [bus 00-ff] end is updated to ff
  pci 8000:00:00.0: [1957:0030] type 00 class 0x0b2000
  pci 8000:00:00.0: reg 0x10: [mem 0xdff00000-0xdfffffff]
  pci 8000:00:01.0: [1af4:1000] type 00 class 0x020000
  pci 8000:00:01.0: reg 0x10: [io  0x0000-0x001f]
  pci 8000:00:01.0: reg 0x14: [mem 0x00000000-0x00000fff]
  pci 8000:00:01.0: reg 0x20: [mem 0x00000000-0x00003fff 64bit pref]
  pci 8000:00:01.0: reg 0x30: [mem 0x00000000-0x0003ffff pref]
  pci_bus 8000:00: busn_res: [bus 00-ff] end is updated to 00
  pci 8000:00:01.0: BAR 6: assigned [mem 0xc00000000-0xc0003ffff pref]
  pci 8000:00:01.0: BAR 4: assigned [mem 0xc00040000-0xc00043fff 64bit pref]
  pci 8000:00:01.0: BAR 1: assigned [mem 0xc00044000-0xc00044fff]
  pci 8000:00:01.0: BAR 0: assigned [io  0x1000-0x101f]
  pci_bus 8000:00: resource 4 [io  0x0000-0xffff]
  pci_bus 8000:00: resource 5 [mem 0xc00000000-0xc1fffffff]
  HugeTLB registered 4.00 MiB page size, pre-allocated 0 pages
  HugeTLB registered 16.0 MiB page size, pre-allocated 0 pages
  HugeTLB registered 64.0 MiB page size, pre-allocated 0 pages
  HugeTLB registered 256 MiB page size, pre-allocated 0 pages
  HugeTLB registered 1.00 GiB page size, pre-allocated 0 pages
  Freescale Elo series DMA driver
  iommu: Default domain type: Translated
  iommu: DMA domain TLB invalidation policy: strict mode
  vgaarb: loaded
  SCSI subsystem initialized
  usbcore: registered new interface driver usbfs
  usbcore: registered new interface driver hub
  usbcore: registered new device driver usb
  pps_core: LinuxPPS API ver. 1 registered
  pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <
giometti@linux.it>
  PTP clock support registered
  Advanced Linux Sound Architecture Driver Initialized.
  clocksource: Switched to clocksource timebase
  NET: Registered PF_INET protocol family
  IP idents hash table entries: 4096 (order: 3, 32768 bytes, linear)
  tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes,
linear)
  TCP established hash table entries: 2048 (order: 1, 8192 bytes, linear)
  TCP bind hash table entries: 2048 (order: 2, 16384 bytes, linear)
  TCP: Hash tables configured (established 2048 bind 2048)
  UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
  UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
  NET: Registered PF_UNIX/PF_LOCAL protocol family
  RPC: Registered named UNIX socket transport module.
  RPC: Registered udp transport module.
  RPC: Registered tcp transport module.
  RPC: Registered tcp NFSv4.1 backchannel transport module.
  PCI: CLS 0 bytes, default 64
  workingset: timestamp_bits=30 max_order=16 bucket_order=0
  squashfs: version 4.0 (2009/01/31) Phillip Lougher
  NFS: Registering the id_resolver key type
  Key type id_resolver registered
  Key type id_legacy registered
  Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
  ntfs: driver 2.1.32 [Flags: R/O].
  jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
  io scheduler mq-deadline registered
  io scheduler kyber registered
  virtio-pci 8000:00:01.0: enabling device (0000 -> 0003)
  Serial: 8250/16550 driver, 6 ports, IRQ sharing enabled
  printk: console [ttyS0] disabled
  serial8250.0: ttyS0 at MMIO 0xfe0004500 (irq = 42, base_baud = 25000000)
is a 16550A
  printk: console [ttyS0] enabled
  printk: console [ttyS0] enabled
  printk: bootconsole [udbg0] disabled
  printk: bootconsole [udbg0] disabled
  ePAPR hypervisor byte channel driver
  brd: module loaded
  loop: module loaded
  st: Version 20160209, fixed bufsize 32768, s/g segs 256
  ucc_geth_driver: QE UCC Gigabit Ethernet Controller
  e1000: Intel(R) PRO/1000 Network Driver
  e1000: Copyright (c) 1999-2006 Intel Corporation.
  e1000e: Intel(R) PRO/1000 Network Driver
  e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
  igb: Intel(R) Gigabit Ethernet Network Driver
  igb: Copyright (c) 2007-2014 Intel Corporation.
  ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
  ehci-pci: EHCI PCI platform driver
  ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
  ohci-pci: OHCI PCI platform driver
  ehci-fsl: Freescale EHCI Host controller driver
  usbcore: registered new interface driver usb-storage
  i2c_dev: i2c /dev entries driver
  mpc-i2c fe0003000.i2c: timeout 1000000 us
  rtc-ds1307 0-0068: registered as rtc0
  rtc-ds1307 0-0068: setting system clock to 2022-10-30T11:27:44 UTC
(1667129264)
  sdhci: Secure Digital Host Controller Interface driver
  sdhci: Copyright(c) Pierre Ossman
  sdhci-pltfm: SDHCI platform and OF driver helper
  Freescale hypervisor management driver
  fsl-hv: no hypervisor found
  mmc0 bounce up to 128 segments into one, max segment size 65536 bytes
  ipip: IPv4 and MPLS over IPv4 tunneling driver
  Initializing XFRM netlink socket
  NET: Registered PF_INET6 protocol family
  Segment Routing with IPv6
  In-situ OAM (IOAM) with IPv6
  sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
  NET: Registered PF_PACKET protocol family
  NET: Registered PF_KEY protocol family
  Key type dns_resolver registered
  drmem: No dynamic reconfiguration memory found
  mmc0: SDHCI controller on fe002e000.sdhc [fe002e000.sdhc] using DMA
  ALSA device list:
    No soundcards found.
  Waiting for root device /dev/mmcblk0...
  mmc0: new high speed SD card at address 4567
  mmcblk0: mmc0:4567 QEMU! 64.0 MiB
  EXT4-fs (mmcblk0): mounted filesystem without journal. Quota mode:
disabled.
  VFS: Mounted root (ext4 filesystem) readonly on device 179:0.
  devtmpfs: mounted
  Freeing unused kernel image (initmem) memory: 396K
  Run /sbin/init as init process
  EXT4-fs (mmcblk0): re-mounted. Quota mode: disabled.
  Starting syslogd: OK
  Starting klogd: OK
  Running sysctl: OK
  Saving random seed: random: dd: uninitialized urandom read (512 bytes
read)
  OK
  Starting network: udhcpc: started, v1.35.0
  udhcpc: broadcasting discover
  udhcpc: broadcasting select for 10.0.2.15, server 10.0.2.2
  random: fast init done
  udhcpc: lease of 10.0.2.15 obtained from 10.0.2.2, lease time 86400
  deleting routers
  adding dns 10.0.2.3
  OK

  Welcome to Buildroot
  buildroot login:


Best regards,
Bernhard
Philippe Mathieu-Daudé Oct. 31, 2022, 12:11 p.m. UTC | #7
On 30/10/22 12:46, Bernhard Beschow wrote:
> 
> 
> On Sun, Oct 30, 2022 at 1:10 AM Philippe Mathieu-Daudé 
> <philmd@linaro.org <mailto:philmd@linaro.org>> wrote:
> 
>     On 29/10/22 20:28, Bernhard Beschow wrote:
>      > Am 29. Oktober 2022 13:04:00 UTC schrieb Bernhard Beschow
>     <shentey@gmail.com <mailto:shentey@gmail.com>>:
>      >> Am 29. Oktober 2022 11:33:51 UTC schrieb Bernhard Beschow
>     <shentey@gmail.com <mailto:shentey@gmail.com>>:
>      >>> Am 27. Oktober 2022 21:40:01 UTC schrieb "Philippe
>     Mathieu-Daudé" <philmd@linaro.org <mailto:philmd@linaro.org>>:
>      >>>> Hi Bernhard,
>      >>>>
>      >>>> On 18/10/22 23:01, Bernhard Beschow wrote:
>      >>>>> Will allow e500 boards to access SD cards using just their
>     own devices.
>      >>>>>
>      >>>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com
>     <mailto:shentey@gmail.com>>
>      >>>>> ---
>      >>>>>    hw/sd/sdhci.c         | 120
>     +++++++++++++++++++++++++++++++++++++++++-
>      >>>>>    include/hw/sd/sdhci.h |   3 ++
>      >>>>>    2 files changed, 122 insertions(+), 1 deletion(-)
> 
>      >>>> So now, I'd create 1 UNIMP region for ESDHC_WML and map it
>      >>>> into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
>      >>>> another UNIMP region of ESDHC_REGISTERS_MAP_SIZE -
>     SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
>      >>>> 0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
>      >>>> hw/arm/bcm2835_peripherals.c.
>      >>>>
>      >>>> But the ESDHC_WML register has address 0x44 and fits inside the
>      >>>> SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
>      >>>> upper part of the SDHC_CAPAB register. These bits are undefined
>      >>>> on the spec v2, which I see you are setting in esdhci_init().
>      >>>> So this register should already return 0, otherwise we have
>      >>>> a bug. Thus we don't need to handle this ESDHC_WML particularly.
>      >>
>      >> My idea here was to catch this unimplemented case in order to
>     indicate this clearly to users. Perhaps it nudges somebody to
>     provide a patch?
>      >>
>      >>>>
>      >>>> And your model is reduced to handling create_unimp() in
>     esdhci_realize().
>      >>>>
>      >>>> Am I missing something?
>      >>>
>      >>> The mmio ops are big endian and need to be aligned to a 4-byte
>     boundary. It took me quite a while to debug this. So shall I just
>     create an additional memory region for the region above
>     SDHC_REGISTERS_MAP_SIZE for ESDHC_DMA_SYSCTL?
>      >>
>      >> All in all I currently don't have a better idea than keeping the
>     custom i/o ops for the standard region and adding an additional
>     unimplemented region for ESDHC_DMA_SYSCTL. I think I'd have to
>     dynamically allocate memory for it where I still need to figure out
>     how not to leak it.
>      >
>      > By simply reusing sdhci_{read,write} in eSDHC's io_ops struct I
>     was able to remove the custom implementations while having big
>     endian and the alignments proper. However, I don't see a way of
>     adding two memory regions - with or without a container. With a
>     container I'd have to somehow preserve the mmio attribute which is
>     initialized by the parent class, re-initialize it with the
>     container, and add the preserved memory region as child. This seems
>     very fragile, esp. since the parent class has created an alias for
>     mmio in sysbus. Without a container, one would have two memory
>     regions that both have to be mapped separately by the caller, i.e.
>     it burdens the caller with an implementation detail.
>      >
>      > Any suggestions?

See 
https://lore.kernel.org/qemu-devel/20221031115402.91912-7-philmd@linaro.org/

>     Can you share branch and how to test?
> 
> 
> QEMU branch: https://github.com/shentok/qemu/tree/e500-flash 
> <https://github.com/shentok/qemu/tree/e500-flash>
> 
> How to test:
> 1. `git clone -b e500 https://github.com/shentok/buildroot.git 
> <https://github.com/shentok/buildroot.git>`
> 2. `cd buildroot`
> 3. `make qemu_ppc_e500mc_defconfig`
> 4. `make`
> 5. `cd output/images`
> 6. `dd if=/dev/zero of=root.img bs=1M count=64 && dd if=rootfs.ext2 
> of=root.img bs=1M conv=notrunc`
> 7. `qemu-system-ppc -M ppce500 -cpu e500mc -m 256 -kernel uImage -append 
> "console=ttyS0 rootwait root=/dev/mmcblk0" -device sd-card,drive=mydrive 
> -drive id=mydrive,if=none,file=root.img,format=raw`

Could you add an Avocado-based test?

>    Welcome to Buildroot
>    buildroot login:

Regards,

Phil.
Bernhard Beschow Nov. 1, 2022, 10:49 a.m. UTC | #8
Am 31. Oktober 2022 12:11:37 UTC schrieb "Philippe Mathieu-Daudé" <philmd@linaro.org>:
>On 30/10/22 12:46, Bernhard Beschow wrote:
>> 
>> 
>> On Sun, Oct 30, 2022 at 1:10 AM Philippe Mathieu-Daudé <philmd@linaro.org <mailto:philmd@linaro.org>> wrote:
>> 
>>     On 29/10/22 20:28, Bernhard Beschow wrote:
>>      > Am 29. Oktober 2022 13:04:00 UTC schrieb Bernhard Beschow
>>     <shentey@gmail.com <mailto:shentey@gmail.com>>:
>>      >> Am 29. Oktober 2022 11:33:51 UTC schrieb Bernhard Beschow
>>     <shentey@gmail.com <mailto:shentey@gmail.com>>:
>>      >>> Am 27. Oktober 2022 21:40:01 UTC schrieb "Philippe
>>     Mathieu-Daudé" <philmd@linaro.org <mailto:philmd@linaro.org>>:
>>      >>>> Hi Bernhard,
>>      >>>>
>>      >>>> On 18/10/22 23:01, Bernhard Beschow wrote:
>>      >>>>> Will allow e500 boards to access SD cards using just their
>>     own devices.
>>      >>>>>
>>      >>>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com
>>     <mailto:shentey@gmail.com>>
>>      >>>>> ---
>>      >>>>>    hw/sd/sdhci.c         | 120
>>     +++++++++++++++++++++++++++++++++++++++++-
>>      >>>>>    include/hw/sd/sdhci.h |   3 ++
>>      >>>>>    2 files changed, 122 insertions(+), 1 deletion(-)
>> 
>>      >>>> So now, I'd create 1 UNIMP region for ESDHC_WML and map it
>>      >>>> into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
>>      >>>> another UNIMP region of ESDHC_REGISTERS_MAP_SIZE -
>>     SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
>>      >>>> 0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
>>      >>>> hw/arm/bcm2835_peripherals.c.
>>      >>>>
>>      >>>> But the ESDHC_WML register has address 0x44 and fits inside the
>>      >>>> SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
>>      >>>> upper part of the SDHC_CAPAB register. These bits are undefined
>>      >>>> on the spec v2, which I see you are setting in esdhci_init().
>>      >>>> So this register should already return 0, otherwise we have
>>      >>>> a bug. Thus we don't need to handle this ESDHC_WML particularly.
>>      >>
>>      >> My idea here was to catch this unimplemented case in order to
>>     indicate this clearly to users. Perhaps it nudges somebody to
>>     provide a patch?
>>      >>
>>      >>>>
>>      >>>> And your model is reduced to handling create_unimp() in
>>     esdhci_realize().
>>      >>>>
>>      >>>> Am I missing something?
>>      >>>
>>      >>> The mmio ops are big endian and need to be aligned to a 4-byte
>>     boundary. It took me quite a while to debug this. So shall I just
>>     create an additional memory region for the region above
>>     SDHC_REGISTERS_MAP_SIZE for ESDHC_DMA_SYSCTL?
>>      >>
>>      >> All in all I currently don't have a better idea than keeping the
>>     custom i/o ops for the standard region and adding an additional
>>     unimplemented region for ESDHC_DMA_SYSCTL. I think I'd have to
>>     dynamically allocate memory for it where I still need to figure out
>>     how not to leak it.
>>      >
>>      > By simply reusing sdhci_{read,write} in eSDHC's io_ops struct I
>>     was able to remove the custom implementations while having big
>>     endian and the alignments proper. However, I don't see a way of
>>     adding two memory regions - with or without a container. With a
>>     container I'd have to somehow preserve the mmio attribute which is
>>     initialized by the parent class, re-initialize it with the
>>     container, and add the preserved memory region as child. This seems
>>     very fragile, esp. since the parent class has created an alias for
>>     mmio in sysbus. Without a container, one would have two memory
>>     regions that both have to be mapped separately by the caller, i.e.
>>     it burdens the caller with an implementation detail.
>>      >
>>      > Any suggestions?
>
>See https://lore.kernel.org/qemu-devel/20221031115402.91912-7-philmd@linaro.org/
>
>>     Can you share branch and how to test?
>> 
>> 
>> QEMU branch: https://github.com/shentok/qemu/tree/e500-flash <https://github.com/shentok/qemu/tree/e500-flash>
>> 
>> How to test:
>> 1. `git clone -b e500 https://github.com/shentok/buildroot.git <https://github.com/shentok/buildroot.git>`
>> 2. `cd buildroot`
>> 3. `make qemu_ppc_e500mc_defconfig`
>> 4. `make`
>> 5. `cd output/images`
>> 6. `dd if=/dev/zero of=root.img bs=1M count=64 && dd if=rootfs.ext2 of=root.img bs=1M conv=notrunc`
>> 7. `qemu-system-ppc -M ppce500 -cpu e500mc -m 256 -kernel uImage -append "console=ttyS0 rootwait root=/dev/mmcblk0" -device sd-card,drive=mydrive -drive id=mydrive,if=none,file=root.img,format=raw`
>
>Could you add an Avocado-based test?

I could give it a try at least. Where would I drop the binaries?

Best regards,
Bernhard
>
>>    Welcome to Buildroot
>>    buildroot login:
>
>Regards,
>
>Phil.
Bernhard Beschow Dec. 16, 2022, 2:38 p.m. UTC | #9
Am 1. November 2022 10:49:20 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>Am 31. Oktober 2022 12:11:37 UTC schrieb "Philippe Mathieu-Daudé" <philmd@linaro.org>:
>>On 30/10/22 12:46, Bernhard Beschow wrote:
>>> 
>>> 
>>> On Sun, Oct 30, 2022 at 1:10 AM Philippe Mathieu-Daudé <philmd@linaro.org <mailto:philmd@linaro.org>> wrote:
>>> 
>>>     On 29/10/22 20:28, Bernhard Beschow wrote:
>>>      > Am 29. Oktober 2022 13:04:00 UTC schrieb Bernhard Beschow
>>>     <shentey@gmail.com <mailto:shentey@gmail.com>>:
>>>      >> Am 29. Oktober 2022 11:33:51 UTC schrieb Bernhard Beschow
>>>     <shentey@gmail.com <mailto:shentey@gmail.com>>:
>>>      >>> Am 27. Oktober 2022 21:40:01 UTC schrieb "Philippe
>>>     Mathieu-Daudé" <philmd@linaro.org <mailto:philmd@linaro.org>>:
>>>      >>>> Hi Bernhard,
>>>      >>>>
>>>      >>>> On 18/10/22 23:01, Bernhard Beschow wrote:
>>>      >>>>> Will allow e500 boards to access SD cards using just their
>>>     own devices.
>>>      >>>>>
>>>      >>>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com
>>>     <mailto:shentey@gmail.com>>
>>>      >>>>> ---
>>>      >>>>>    hw/sd/sdhci.c         | 120
>>>     +++++++++++++++++++++++++++++++++++++++++-
>>>      >>>>>    include/hw/sd/sdhci.h |   3 ++
>>>      >>>>>    2 files changed, 122 insertions(+), 1 deletion(-)
>>> 
>>>      >>>> So now, I'd create 1 UNIMP region for ESDHC_WML and map it
>>>      >>>> into SDHC_REGISTERS_MAP (s->iomem) with priority 1, and add
>>>      >>>> another UNIMP region of ESDHC_REGISTERS_MAP_SIZE -
>>>     SDHC_REGISTERS_MAP_SIZE (= 0x310) and map it normally at offset
>>>      >>>> 0x100 (SDHC_REGISTERS_MAP_SIZE). Look at create_unimp() in
>>>      >>>> hw/arm/bcm2835_peripherals.c.
>>>      >>>>
>>>      >>>> But the ESDHC_WML register has address 0x44 and fits inside the
>>>      >>>> SDHC_REGISTERS_MAP region, so likely belong there. 0x44 is the
>>>      >>>> upper part of the SDHC_CAPAB register. These bits are undefined
>>>      >>>> on the spec v2, which I see you are setting in esdhci_init().
>>>      >>>> So this register should already return 0, otherwise we have
>>>      >>>> a bug. Thus we don't need to handle this ESDHC_WML particularly.
>>>      >>
>>>      >> My idea here was to catch this unimplemented case in order to
>>>     indicate this clearly to users. Perhaps it nudges somebody to
>>>     provide a patch?
>>>      >>
>>>      >>>>
>>>      >>>> And your model is reduced to handling create_unimp() in
>>>     esdhci_realize().
>>>      >>>>
>>>      >>>> Am I missing something?
>>>      >>>
>>>      >>> The mmio ops are big endian and need to be aligned to a 4-byte
>>>     boundary. It took me quite a while to debug this. So shall I just
>>>     create an additional memory region for the region above
>>>     SDHC_REGISTERS_MAP_SIZE for ESDHC_DMA_SYSCTL?
>>>      >>
>>>      >> All in all I currently don't have a better idea than keeping the
>>>     custom i/o ops for the standard region and adding an additional
>>>     unimplemented region for ESDHC_DMA_SYSCTL. I think I'd have to
>>>     dynamically allocate memory for it where I still need to figure out
>>>     how not to leak it.
>>>      >
>>>      > By simply reusing sdhci_{read,write} in eSDHC's io_ops struct I
>>>     was able to remove the custom implementations while having big
>>>     endian and the alignments proper. However, I don't see a way of
>>>     adding two memory regions - with or without a container. With a
>>>     container I'd have to somehow preserve the mmio attribute which is
>>>     initialized by the parent class, re-initialize it with the
>>>     container, and add the preserved memory region as child. This seems
>>>     very fragile, esp. since the parent class has created an alias for
>>>     mmio in sysbus. Without a container, one would have two memory
>>>     regions that both have to be mapped separately by the caller, i.e.
>>>     it burdens the caller with an implementation detail.
>>>      >
>>>      > Any suggestions?
>>
>>See https://lore.kernel.org/qemu-devel/20221031115402.91912-7-philmd@linaro.org/
>>
>>>     Can you share branch and how to test?
>>> 
>>> 
>>> QEMU branch: https://github.com/shentok/qemu/tree/e500-flash <https://github.com/shentok/qemu/tree/e500-flash>
>>> 
>>> How to test:
>>> 1. `git clone -b e500 https://github.com/shentok/buildroot.git <https://github.com/shentok/buildroot.git>`
>>> 2. `cd buildroot`
>>> 3. `make qemu_ppc_e500mc_defconfig`
>>> 4. `make`
>>> 5. `cd output/images`
>>> 6. `dd if=/dev/zero of=root.img bs=1M count=64 && dd if=rootfs.ext2 of=root.img bs=1M conv=notrunc`
>>> 7. `qemu-system-ppc -M ppce500 -cpu e500mc -m 256 -kernel uImage -append "console=ttyS0 rootwait root=/dev/mmcblk0" -device sd-card,drive=mydrive -drive id=mydrive,if=none,file=root.img,format=raw`
>>
>>Could you add an Avocado-based test?
>
>I could give it a try at least. Where would I drop the binaries?

Looks like Cederic already had a repo [1]. Let's see what I can do.

Best regards,
Bernhard

[1] https://github.com/legoater/qemu-ppc-boot/tree/main/buildroot

>
>Best regards,
>Bernhard
>>
>>>    Welcome to Buildroot
>>>    buildroot login:
>>
>>Regards,
>>
>>Phil.
>
diff mbox series

Patch

diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 306070c872..8d8ad9ff24 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -1369,6 +1369,7 @@  void sdhci_initfn(SDHCIState *s)
     s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
 
     s->io_ops = &sdhci_mmio_ops;
+    s->io_registers_map_size = SDHC_REGISTERS_MAP_SIZE;
 }
 
 void sdhci_uninitfn(SDHCIState *s)
@@ -1392,7 +1393,7 @@  void sdhci_common_realize(SDHCIState *s, Error **errp)
     s->fifo_buffer = g_malloc0(s->buf_maxsz);
 
     memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci",
-                          SDHC_REGISTERS_MAP_SIZE);
+                          s->io_registers_map_size);
 }
 
 void sdhci_common_unrealize(SDHCIState *s)
@@ -1575,6 +1576,122 @@  static const TypeInfo sdhci_bus_info = {
     .class_init = sdhci_bus_class_init,
 };
 
+/* --- qdev Freescale eSDHC --- */
+
+/* Watermark Level Register */
+#define ESDHC_WML                    0x44
+
+/* Control Register for DMA transfer */
+#define ESDHC_DMA_SYSCTL            0x40c
+
+#define ESDHC_REGISTERS_MAP_SIZE    0x410
+
+static uint64_t esdhci_read(void *opaque, hwaddr offset, unsigned size)
+{
+    uint64_t ret;
+
+    switch (offset) {
+    case SDHC_SYSAD:
+    case SDHC_BLKSIZE:
+    case SDHC_ARGUMENT:
+    case SDHC_TRNMOD:
+    case SDHC_RSPREG0:
+    case SDHC_RSPREG1:
+    case SDHC_RSPREG2:
+    case SDHC_RSPREG3:
+    case SDHC_BDATA:
+    case SDHC_PRNSTS:
+    case SDHC_HOSTCTL:
+    case SDHC_CLKCON:
+    case SDHC_NORINTSTS:
+    case SDHC_NORINTSTSEN:
+    case SDHC_NORINTSIGEN:
+    case SDHC_ACMD12ERRSTS:
+    case SDHC_CAPAB:
+    case SDHC_SLOT_INT_STATUS:
+        ret = sdhci_read(opaque, offset, size);
+        break;
+
+    case ESDHC_WML:
+    case ESDHC_DMA_SYSCTL:
+        ret = 0;
+        qemu_log_mask(LOG_UNIMP, "ESDHC rd @0x%02" HWADDR_PRIx
+                      " not implemented\n", offset);
+        break;
+
+    default:
+        ret = 0;
+        qemu_log_mask(LOG_GUEST_ERROR, "ESDHC rd @0x%02" HWADDR_PRIx
+                      " unknown offset\n", offset);
+        break;
+    }
+
+    return ret;
+}
+
+static void esdhci_write(void *opaque, hwaddr offset, uint64_t val,
+                         unsigned size)
+{
+    switch (offset) {
+    case SDHC_SYSAD:
+    case SDHC_BLKSIZE:
+    case SDHC_ARGUMENT:
+    case SDHC_TRNMOD:
+    case SDHC_BDATA:
+    case SDHC_HOSTCTL:
+    case SDHC_CLKCON:
+    case SDHC_NORINTSTS:
+    case SDHC_NORINTSTSEN:
+    case SDHC_NORINTSIGEN:
+    case SDHC_FEAER:
+        sdhci_write(opaque, offset, val, size);
+        break;
+
+    case ESDHC_WML:
+    case ESDHC_DMA_SYSCTL:
+        qemu_log_mask(LOG_UNIMP, "ESDHC wr @0x%02" HWADDR_PRIx " <- 0x%08lx "
+                      "not implemented\n", offset, val);
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "ESDHC wr @0x%02" HWADDR_PRIx
+                      " <- 0x%08lx unknown offset\n", offset, val);
+        break;
+    }
+}
+
+static const MemoryRegionOps esdhc_mmio_ops = {
+    .read = esdhci_read,
+    .write = esdhci_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void esdhci_init(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    SDHCIState *s = SYSBUS_SDHCI(obj);
+
+    s->io_ops = &esdhc_mmio_ops;
+    s->io_registers_map_size = ESDHC_REGISTERS_MAP_SIZE;
+
+    /*
+     * Compatible with:
+     * - SD Host Controller Specification Version 2.0 Part A2
+     */
+    qdev_prop_set_uint8(dev, "sd-spec-version", 2);
+}
+
+static const TypeInfo esdhc_info = {
+    .name = TYPE_FSL_ESDHC,
+    .parent = TYPE_SYSBUS_SDHCI,
+    .instance_init = esdhci_init,
+};
+
 /* --- qdev i.MX eSDHC --- */
 
 #define USDHC_MIX_CTRL                  0x48
@@ -1907,6 +2024,7 @@  static void sdhci_register_types(void)
 {
     type_register_static(&sdhci_sysbus_info);
     type_register_static(&sdhci_bus_info);
+    type_register_static(&esdhc_info);
     type_register_static(&imx_usdhc_info);
     type_register_static(&sdhci_s3c_info);
 }
diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h
index 01a64c5442..5b32e83eee 100644
--- a/include/hw/sd/sdhci.h
+++ b/include/hw/sd/sdhci.h
@@ -45,6 +45,7 @@  struct SDHCIState {
     AddressSpace *dma_as;
     MemoryRegion *dma_mr;
     const MemoryRegionOps *io_ops;
+    uint64_t io_registers_map_size;
 
     QEMUTimer *insert_timer;       /* timer for 'changing' sd card. */
     QEMUTimer *transfer_timer;
@@ -122,6 +123,8 @@  DECLARE_INSTANCE_CHECKER(SDHCIState, PCI_SDHCI,
 DECLARE_INSTANCE_CHECKER(SDHCIState, SYSBUS_SDHCI,
                          TYPE_SYSBUS_SDHCI)
 
+#define TYPE_FSL_ESDHC "fsl-esdhc"
+
 #define TYPE_IMX_USDHC "imx-usdhc"
 
 #define TYPE_S3C_SDHCI "s3c-sdhci"