diff mbox

[v3,12/12] i.MX: Add sabrelite i.MX6 emulation.

Message ID bdd266de649a0d05e7373dd147e58af33677a012.1456868959.git.jcd@tribudubois.net (mailing list archive)
State New, archived
Headers show

Commit Message

Jean-Christophe Dubois March 1, 2016, 10:27 p.m. UTC
The sabrelite supports one SPI FLASH memory on SPI1

Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---

Changes since v1:
 * output a message and exit if RAM size is unsupported.

Changes since v2:
 * Added include "qemu/osdep.h"
 * Added access to controllers through properties.

 hw/arm/Makefile.objs |   2 +-
 hw/arm/sabrelite.c   | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+), 1 deletion(-)
 create mode 100644 hw/arm/sabrelite.c

Comments

Peter Maydell March 10, 2016, 10:38 a.m. UTC | #1
On 2 March 2016 at 05:27, Jean-Christophe Dubois <jcd@tribudubois.net> wrote:
> The sabrelite supports one SPI FLASH memory on SPI1
>
> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
> ---
>
> +
> +    {
> +        /* Add the sst25vf016b NOR FLASH memory to first SPI */
> +        Object *spi_dev;
> +
> +        spi_dev = object_resolve_path_component(OBJECT(&s->soc), "spi1");
> +        if (spi_dev) {
> +            SSIBus *spi_bus;
> +
> +            spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");

This looks odd. You should just be able to do
 spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), "spi1");
without using object_resolve_path_component() to try to find an
SPI device object, because your SoC device should have alias properties
which provide access to its SPI subcomponents' SPI buses.
See hw/arm/xlnx-ep108.c for an example of the board code for this and
hw/arm/xlnx-zynqmp.c for the SoC code which calls
object_property_add_alias() to set up the aliases.

> +            if (spi_bus) {
> +                DeviceState *flash_dev;
> +
> +                flash_dev = ssi_create_slave(spi_bus, "sst25vf016b");
> +                if (flash_dev) {
> +                    qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev,
> +                                                              SSI_GPIO_CS, 0);
> +                    sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
> +                }
> +            }
> +        }
> +    }

thanks
-- PMM
Jean-Christophe Dubois March 10, 2016, 7:24 p.m. UTC | #2
Le 10/03/2016 11:38, Peter Maydell a écrit :
> On 2 March 2016 at 05:27, Jean-Christophe Dubois <jcd@tribudubois.net> wrote:
>> The sabrelite supports one SPI FLASH memory on SPI1
>>
>> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
>> ---
>>
>> +
>> +    {
>> +        /* Add the sst25vf016b NOR FLASH memory to first SPI */
>> +        Object *spi_dev;
>> +
>> +        spi_dev = object_resolve_path_component(OBJECT(&s->soc), "spi1");
>> +        if (spi_dev) {
>> +            SSIBus *spi_bus;
>> +
>> +            spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");
> This looks odd. You should just be able to do
>   spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), "spi1");
> without using object_resolve_path_component() to try to find an
> SPI device object, because your SoC device should have alias properties
> which provide access to its SPI subcomponents' SPI buses.
> See hw/arm/xlnx-ep108.c for an example of the board code for this and
> hw/arm/xlnx-zynqmp.c for the SoC code which calls
> object_property_add_alias() to set up the aliases.

I certainly could do as you proposed.

The problem is that I also need the spi_dev device for the 
sysbus_connect_irq() call below.

My spi_dev is referenced as "spi1" in the i.MX6 doc and I added a 'spi1" 
property for it in the i.MX6 soc.

Once I have the spi_dev device it is trivial to retrieve the spi_bus 
attached to it.

So, yes this is not in line with what is done in xlnx-zynqmp.c but the 
need is a bit different.

JC

>
>> +            if (spi_bus) {
>> +                DeviceState *flash_dev;
>> +
>> +                flash_dev = ssi_create_slave(spi_bus, "sst25vf016b");
>> +                if (flash_dev) {
>> +                    qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev,
>> +                                                              SSI_GPIO_CS, 0);
>> +                    sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
>> +                }
>> +            }
>> +        }
>> +    }
> thanks
> -- PMM
>
Peter Maydell March 10, 2016, 11:57 p.m. UTC | #3
On 11 March 2016 at 02:24, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
> Le 10/03/2016 11:38, Peter Maydell a écrit :
>>
>> On 2 March 2016 at 05:27, Jean-Christophe Dubois <jcd@tribudubois.net>
>> wrote:
>>>
>>> The sabrelite supports one SPI FLASH memory on SPI1
>>>
>>> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
>>> ---
>>>
>>> +
>>> +    {
>>> +        /* Add the sst25vf016b NOR FLASH memory to first SPI */
>>> +        Object *spi_dev;
>>> +
>>> +        spi_dev = object_resolve_path_component(OBJECT(&s->soc),
>>> "spi1");
>>> +        if (spi_dev) {
>>> +            SSIBus *spi_bus;
>>> +
>>> +            spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev),
>>> "spi");
>>
>> This looks odd. You should just be able to do
>>   spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), "spi1");
>> without using object_resolve_path_component() to try to find an
>> SPI device object, because your SoC device should have alias properties
>> which provide access to its SPI subcomponents' SPI buses.
>> See hw/arm/xlnx-ep108.c for an example of the board code for this and
>> hw/arm/xlnx-zynqmp.c for the SoC code which calls
>> object_property_add_alias() to set up the aliases.
>
>
> I certainly could do as you proposed.
>
> The problem is that I also need the spi_dev device for the
> sysbus_connect_irq() call below.
>
> My spi_dev is referenced as "spi1" in the i.MX6 doc and I added a 'spi1"
> property for it in the i.MX6 soc.
>
> Once I have the spi_dev device it is trivial to retrieve the spi_bus
> attached to it.
>
> So, yes this is not in line with what is done in xlnx-zynqmp.c but the need
> is a bit different.

I think the SoC should probably have an externally-facing IRQ line
which it wires up internally to the SPI's IRQ line.
(This corresponds basically to what happens in h/w -- the SoC's
interfaces are defined by it even though many of them may be
directly wired up to some internal component it has, but from
outside the SoC you don't get access to the whole of the internal
component.)

thanks
-- PMM
Jean-Christophe Dubois March 15, 2016, 9:40 p.m. UTC | #4
Le 11/03/2016 00:57, Peter Maydell a écrit :
> On 11 March 2016 at 02:24, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
>> Le 10/03/2016 11:38, Peter Maydell a écrit :
>>> On 2 March 2016 at 05:27, Jean-Christophe Dubois <jcd@tribudubois.net>
>>> wrote:
>>>> The sabrelite supports one SPI FLASH memory on SPI1
>>>>
>>>> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
>>>> ---
>>>>
>>>> +
>>>> +    {
>>>> +        /* Add the sst25vf016b NOR FLASH memory to first SPI */
>>>> +        Object *spi_dev;
>>>> +
>>>> +        spi_dev = object_resolve_path_component(OBJECT(&s->soc),
>>>> "spi1");
>>>> +        if (spi_dev) {
>>>> +            SSIBus *spi_bus;
>>>> +
>>>> +            spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev),
>>>> "spi");
>>> This looks odd. You should just be able to do
>>>    spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), "spi1");
>>> without using object_resolve_path_component() to try to find an
>>> SPI device object, because your SoC device should have alias properties
>>> which provide access to its SPI subcomponents' SPI buses.
>>> See hw/arm/xlnx-ep108.c for an example of the board code for this and
>>> hw/arm/xlnx-zynqmp.c for the SoC code which calls
>>> object_property_add_alias() to set up the aliases.
>>
>> I certainly could do as you proposed.
>>
>> The problem is that I also need the spi_dev device for the
>> sysbus_connect_irq() call below.
>>
>> My spi_dev is referenced as "spi1" in the i.MX6 doc and I added a 'spi1"
>> property for it in the i.MX6 soc.
>>
>> Once I have the spi_dev device it is trivial to retrieve the spi_bus
>> attached to it.
>>
>> So, yes this is not in line with what is done in xlnx-zynqmp.c but the need
>> is a bit different.
> I think the SoC should probably have an externally-facing IRQ line
> which it wires up internally to the SPI's IRQ line.
> (This corresponds basically to what happens in h/w -- the SoC's
> interfaces are defined by it even though many of them may be
> directly wired up to some internal component it has, but from
> outside the SoC you don't get access to the whole of the internal
> component.)

Well, each SPI controller has 4 possible CS lines to external devices 
and I have 5 SPI controllers.

This makes 20 externally facing IRQ lines (these are output lines) to 
add to the i.MX6 soc object as properties (with a meaningful naming 
convention).

And anyway, what I need to pass to sysbus_connect_irq() is a 
SYS_BUS_DEVICE and not an IRQ line ...

So do you mean I should define the 20 external lines (properties) and 
wire all of them up with sysbus_connect_irq() in the i.MX6 SOC 
implementation (fsl-imx6.c)?

Then How to you "connect" this externally facing line to the selected 
device CS line (here a FLASH memory) in sabrelite?

JC


>
> thanks
> -- PMM
>
Peter Maydell March 16, 2016, 6:32 a.m. UTC | #5
On 15 March 2016 at 21:40, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
> Well, each SPI controller has 4 possible CS lines to external devices and I
> have 5 SPI controllers.
>
> This makes 20 externally facing IRQ lines (these are output lines) to add to
> the i.MX6 soc object as properties (with a meaningful naming convention).
>
> And anyway, what I need to pass to sysbus_connect_irq() is a SYS_BUS_DEVICE
> and not an IRQ line ...

sysbus_connect_irq() is just syntactic sugar for a
qdev_connect_gpio_out_named() call on the sysbus device; in this case
you'd have a bunch of named gpio lines on the SoC device and use
  qdev_connect_gpio_out_named(soc_device, SOC_CS_WHATEVER, 1, cs_line);

> So do you mean I should define the 20 external lines (properties) and wire
> all of them up with sysbus_connect_irq() in the i.MX6 SOC implementation
> (fsl-imx6.c)?

If you use qdev_init_gpio_out_named() in the SPI controller (which
is probably a good idea anyway, chip selects aren't IRQs so using the
gpio functions is clearer naming) then you ought to be able to create
the appropriate aliases, since gpios are link properties. However I
can't quite figure out how this is supposed to work -- Peter C ?

(There's a qdev_pass_gpios() which is almost right but that operates
on all gpios rather than a specified subset.)

thanks
-- PMM
Peter Maydell March 16, 2016, 11:28 a.m. UTC | #6
On 16 March 2016 at 06:32, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 15 March 2016 at 21:40, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
>> So do you mean I should define the 20 external lines (properties) and wire
>> all of them up with sysbus_connect_irq() in the i.MX6 SOC implementation
>> (fsl-imx6.c)?
>
> If you use qdev_init_gpio_out_named() in the SPI controller (which
> is probably a good idea anyway, chip selects aren't IRQs so using the
> gpio functions is clearer naming) then you ought to be able to create
> the appropriate aliases, since gpios are link properties. However I
> can't quite figure out how this is supposed to work -- Peter C ?

On the other hand if there isn't an obvious way to do this I'd be OK
with taking this series with this part of the code the way you have it
now, and we can clean it up later. We're already well into softfreeze
so I'd rather we didn't delay too long...

thanks
-- PMM
diff mbox

Patch

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 4a3011a..d244d10 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -16,4 +16,4 @@  obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
 obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
 obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
-obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o
+obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
new file mode 100644
index 0000000..86d79f8
--- /dev/null
+++ b/hw/arm/sabrelite.c
@@ -0,0 +1,117 @@ 
+/*
+ * SABRELITE Board System emulation.
+ *
+ * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This code is licensed under the GPL, version 2 or later.
+ * See the file `COPYING' in the top level directory.
+ *
+ * It (partially) emulates a sabrelite board, with a Freescale
+ * i.MX6 SoC
+ */
+
+#include "qemu/osdep.h"
+#include "hw/arm/fsl-imx6.h"
+#include "hw/boards.h"
+#include "qemu/error-report.h"
+#include "exec/address-spaces.h"
+#include "net/net.h"
+#include "hw/devices.h"
+#include "hw/char/serial.h"
+#include "sysemu/qtest.h"
+
+typedef struct IMX6Sabrelite {
+    FslIMX6State soc;
+    MemoryRegion ram;
+} IMX6Sabrelite;
+
+static struct arm_boot_info sabrelite_binfo = {
+    /* DDR memory start */
+    .loader_start = FSL_IMX6_MMDC_ADDR,
+    /* No board ID, we boot from DT tree */
+    .board_id = -1,
+};
+
+/* No need to do any particular setup for secondary boot */
+static void sabrelite_write_secondary(ARMCPU *cpu,
+                                      const struct arm_boot_info *info)
+{
+}
+
+/* Secondary cores are reset through SRC device */
+static void sabrelite_reset_secondary(ARMCPU *cpu,
+                                      const struct arm_boot_info *info)
+{
+}
+
+static void sabrelite_init(MachineState *machine)
+{
+    IMX6Sabrelite *s = g_new0(IMX6Sabrelite, 1);
+    Error *err = NULL;
+
+    /* Check the amount of memory is compatible with the SOC */
+    if (machine->ram_size > FSL_IMX6_MMDC_SIZE) {
+        error_report("RAM size " RAM_ADDR_FMT " above max supported (%08x)",
+                     machine->ram_size, FSL_IMX6_MMDC_SIZE);
+        exit(1);
+    }
+
+    object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX6);
+    object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
+                              &error_abort);
+
+    object_property_set_bool(OBJECT(&s->soc), true, "realized", &err);
+    if (err != NULL) {
+        error_report("%s", error_get_pretty(err));
+        exit(1);
+    }
+
+    memory_region_allocate_system_memory(&s->ram, NULL, "sabrelite.ram",
+                                         machine->ram_size);
+    memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR,
+                                &s->ram);
+
+    {
+        /* Add the sst25vf016b NOR FLASH memory to first SPI */
+        Object *spi_dev;
+
+        spi_dev = object_resolve_path_component(OBJECT(&s->soc), "spi1");
+        if (spi_dev) {
+            SSIBus *spi_bus;
+
+            spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");
+            if (spi_bus) {
+                DeviceState *flash_dev;
+
+                flash_dev = ssi_create_slave(spi_bus, "sst25vf016b");
+                if (flash_dev) {
+                    qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev,
+                                                              SSI_GPIO_CS, 0);
+                    sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
+                }
+            }
+        }
+    }
+
+    sabrelite_binfo.ram_size = machine->ram_size;
+    sabrelite_binfo.kernel_filename = machine->kernel_filename;
+    sabrelite_binfo.kernel_cmdline = machine->kernel_cmdline;
+    sabrelite_binfo.initrd_filename = machine->initrd_filename;
+    sabrelite_binfo.nb_cpus = smp_cpus;
+    sabrelite_binfo.secure_boot = true;
+    sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary;
+    sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary;
+
+    if (!qtest_enabled()) {
+        arm_load_kernel(&s->soc.cpu[0], &sabrelite_binfo);
+    }
+}
+
+static void sabrelite_machine_init(MachineClass *mc)
+{
+    mc->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)";
+    mc->init = sabrelite_init;
+    mc->max_cpus = FSL_IMX6_NUM_CPUS;
+}
+
+DEFINE_MACHINE("sabrelite", sabrelite_machine_init)