mirror of https://github.com/xemu-project/xemu.git
target-arm queue:
* MAINTAINERS: Update STM32L4x5 and B-L475E-IOT01A maintainers * hw/arm/xlnx: Connect secondary CGEM IRQs * m25p80: Add SFDP table for mt35xu01g flash * target/arm: Avoid target_ulong for physical address lookups * hw/ssi/xilinx_spips: Fix flash erase assert in dual parallel configuration * hw: fix memory leak in IRQState allocation * hw/sd/sdcard: Fix handling of disabled boot partitions * arm: Remove deprecated board models -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmb8JW8ZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3m85D/9W5E4BQd4mG0JPT+OcCRP/ MQGXsU6fOm3mtYfehXMwnJf2POOK0t/IC5W1mOGmIV6R4ABv2il3cXvQznCpcKY3 eRmMLn4tfI2bn8zJmkIMY5am7j7G3RJzktz8iQ3bstNwD3pYU46tr36iup7vU71b Z5Q3+uauBoUo/9rw5jgjjoZ9Z3Ay2RECsZc/vD6NIN0kh2TYgdpitR47J8jhS3ZX +laqimnRl5wQpe0TIYzpdFr82CXfT62WfQ/+6D6xftbTrV1gfLWesc7hHsgw7Sem ST+nX+0Wr0UfBvsNN4ldi4jB4FfMeUCPX4wBbkKaYyD7bYFnoiz8RPYCxrHlKqeL 9P7+LuA+h+odIcsCza9zUSpQIu4gGIuovmnjz6rbD8m6poV0OmU/Ncj4JC9hGJNi Y1utyFELsvpdQhHP1M2K0qEgO3q/fJyzgA5LXkeXLVozjJM6DX7deVdXjwcBWqeI McJwe/C1TZ/WQlssrWmx6+naA8sygrsbo98a7X+DVsZ0ka6ofZSKkr7aHd3+dia+ a4KbiMX6ChqZxPbIB+m4GnOkCDefu098rXlOu4gkMdzyQT/sm7wmVzQ3YsW3jVqx DNG6Mrg6OVvevXQysdLkJIemnM9YeLxf0lEJ/NpkyGQ7LlmdBws+p1ooCvuvg2Ua CRFY1tuUfWrshpziF1cT4A== =q4iF -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20241001' of https://git.linaro.org/people/pmaydell/qemu-arm into staging target-arm queue: * MAINTAINERS: Update STM32L4x5 and B-L475E-IOT01A maintainers * hw/arm/xlnx: Connect secondary CGEM IRQs * m25p80: Add SFDP table for mt35xu01g flash * target/arm: Avoid target_ulong for physical address lookups * hw/ssi/xilinx_spips: Fix flash erase assert in dual parallel configuration * hw: fix memory leak in IRQState allocation * hw/sd/sdcard: Fix handling of disabled boot partitions * arm: Remove deprecated board models # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmb8JW8ZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3m85D/9W5E4BQd4mG0JPT+OcCRP/ # MQGXsU6fOm3mtYfehXMwnJf2POOK0t/IC5W1mOGmIV6R4ABv2il3cXvQznCpcKY3 # eRmMLn4tfI2bn8zJmkIMY5am7j7G3RJzktz8iQ3bstNwD3pYU46tr36iup7vU71b # Z5Q3+uauBoUo/9rw5jgjjoZ9Z3Ay2RECsZc/vD6NIN0kh2TYgdpitR47J8jhS3ZX # +laqimnRl5wQpe0TIYzpdFr82CXfT62WfQ/+6D6xftbTrV1gfLWesc7hHsgw7Sem # ST+nX+0Wr0UfBvsNN4ldi4jB4FfMeUCPX4wBbkKaYyD7bYFnoiz8RPYCxrHlKqeL # 9P7+LuA+h+odIcsCza9zUSpQIu4gGIuovmnjz6rbD8m6poV0OmU/Ncj4JC9hGJNi # Y1utyFELsvpdQhHP1M2K0qEgO3q/fJyzgA5LXkeXLVozjJM6DX7deVdXjwcBWqeI # McJwe/C1TZ/WQlssrWmx6+naA8sygrsbo98a7X+DVsZ0ka6ofZSKkr7aHd3+dia+ # a4KbiMX6ChqZxPbIB+m4GnOkCDefu098rXlOu4gkMdzyQT/sm7wmVzQ3YsW3jVqx # DNG6Mrg6OVvevXQysdLkJIemnM9YeLxf0lEJ/NpkyGQ7LlmdBws+p1ooCvuvg2Ua # CRFY1tuUfWrshpziF1cT4A== # =q4iF # -----END PGP SIGNATURE----- # gpg: Signature made Tue 01 Oct 2024 17:38:07 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20241001' of https://git.linaro.org/people/pmaydell/qemu-arm: (54 commits) hw: Remove omap2 specific defines and enums hw/dma: Remove omap_dma4 device hw/misc/omap_clk: Remove OMAP2-specifics hw/misc: Remove omap_l4 device hw/display: Remove omap_dss hw/misc: Remove omap_tap device hw/ssi: Remove omap_mcspi hw/timer: Remove omap_synctimer hw/timer: Remove omap_gptimer hw/misc: Remove omap_gpmc hw/misc: Remove omap_sdrc device hw/sd: Remove omap2_mmc device hw/intc: Remove omap2-intc device hw/char: Remove omap2_uart hw/gpio: Remove TYPE_OMAP2_GPIO hw/arm: Remove omap2.c docs: Document removal of old Arm boards hw/usb: Remove MUSB USB host controller hw/usb: Remove tusb6010 USB controller hw/block: Remove OneNAND device ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
062cfce8d4
99
MAINTAINERS
99
MAINTAINERS
|
@ -706,6 +706,14 @@ F: include/hw/timer/armv7m_systick.h
|
|||
F: include/hw/misc/armv7m_ras.h
|
||||
F: tests/qtest/test-arm-mptimer.c
|
||||
|
||||
B-L475E-IOT01A IoT Node
|
||||
M: Samuel Tardieu <sam@rfc1149.net>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/b-l475e-iot01a.c
|
||||
F: hw/display/dm163.c
|
||||
F: tests/qtest/dm163-test.c
|
||||
|
||||
Exynos
|
||||
M: Igor Mitsyanko <i.mitsyanko@gmail.com>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
|
@ -742,14 +750,6 @@ S: Maintained
|
|||
F: hw/rtc/goldfish_rtc.c
|
||||
F: include/hw/rtc/goldfish_rtc.h
|
||||
|
||||
Gumstix
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
R: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/arm/gumstix.c
|
||||
F: docs/system/arm/gumstix.rst
|
||||
|
||||
i.MX25 PDK
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
R: Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
|
@ -870,32 +870,6 @@ F: pc-bios/npcm7xx_bootrom.bin
|
|||
F: roms/vbootrom
|
||||
F: docs/system/arm/nuvoton.rst
|
||||
|
||||
nSeries
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/arm/nseries.c
|
||||
F: hw/display/blizzard.c
|
||||
F: hw/input/lm832x.c
|
||||
F: hw/input/tsc2005.c
|
||||
F: hw/misc/cbus.c
|
||||
F: hw/rtc/twl92230.c
|
||||
F: include/hw/display/blizzard.h
|
||||
F: include/hw/input/lm832x.h
|
||||
F: include/hw/input/tsc2xxx.h
|
||||
F: include/hw/misc/cbus.h
|
||||
F: tests/avocado/machine_arm_n8x0.py
|
||||
F: docs/system/arm/nseries.rst
|
||||
|
||||
Palm
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/arm/palm.c
|
||||
F: hw/input/tsc210x.c
|
||||
F: include/hw/input/tsc2xxx.h
|
||||
F: docs/system/arm/palm.rst
|
||||
|
||||
Raspberry Pi
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
R: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||
|
@ -921,28 +895,6 @@ F: hw/intc/realview_gic.c
|
|||
F: include/hw/intc/realview_gic.h
|
||||
F: docs/system/arm/realview.rst
|
||||
|
||||
PXA2XX
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/arm/mainstone.c
|
||||
F: hw/arm/spitz.c
|
||||
F: hw/arm/tosa.c
|
||||
F: hw/arm/z2.c
|
||||
F: hw/*/pxa2xx*
|
||||
F: hw/display/tc6393xb.c
|
||||
F: hw/gpio/max7310.c
|
||||
F: hw/gpio/zaurus.c
|
||||
F: hw/input/ads7846.c
|
||||
F: hw/misc/mst_fpga.c
|
||||
F: hw/adc/max111x.c
|
||||
F: include/hw/adc/max111x.h
|
||||
F: include/hw/arm/pxa.h
|
||||
F: include/hw/arm/sharpsl.h
|
||||
F: include/hw/display/tc6393xb.h
|
||||
F: docs/system/arm/xscale.rst
|
||||
F: docs/system/arm/mainstone.rst
|
||||
|
||||
SABRELITE / i.MX6
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
R: Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
|
@ -979,6 +931,8 @@ L: qemu-arm@nongnu.org
|
|||
S: Odd Fixes
|
||||
F: hw/arm/collie.c
|
||||
F: hw/arm/strongarm*
|
||||
F: hw/gpio/zaurus.c
|
||||
F: include/hw/arm/sharpsl.h
|
||||
F: docs/system/arm/collie.rst
|
||||
|
||||
Stellaris
|
||||
|
@ -991,6 +945,19 @@ F: include/hw/input/gamepad.h
|
|||
F: include/hw/timer/stellaris-gptm.h
|
||||
F: docs/system/arm/stellaris.rst
|
||||
|
||||
STM32L4x5 SoC Family
|
||||
M: Samuel Tardieu <sam@rfc1149.net>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/stm32l4x5_soc.c
|
||||
F: hw/char/stm32l4x5_usart.c
|
||||
F: hw/misc/stm32l4x5_exti.c
|
||||
F: hw/misc/stm32l4x5_syscfg.c
|
||||
F: hw/misc/stm32l4x5_rcc.c
|
||||
F: hw/gpio/stm32l4x5_gpio.c
|
||||
F: include/hw/*/stm32l4x5_*.h
|
||||
F: tests/qtest/stm32l4x5*
|
||||
|
||||
STM32VLDISCOVERY
|
||||
M: Alexandre Iooss <erdnaxe@crans.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
|
@ -1118,26 +1085,6 @@ L: qemu-arm@nongnu.org
|
|||
S: Maintained
|
||||
F: hw/arm/olimex-stm32-h405.c
|
||||
|
||||
STM32L4x5 SoC Family
|
||||
M: Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
M: Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/stm32l4x5_soc.c
|
||||
F: hw/char/stm32l4x5_usart.c
|
||||
F: hw/misc/stm32l4x5_exti.c
|
||||
F: hw/misc/stm32l4x5_syscfg.c
|
||||
F: hw/misc/stm32l4x5_rcc.c
|
||||
F: hw/gpio/stm32l4x5_gpio.c
|
||||
F: include/hw/*/stm32l4x5_*.h
|
||||
|
||||
B-L475E-IOT01A IoT Node
|
||||
M: Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
M: Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/b-l475e-iot01a.c
|
||||
|
||||
SmartFusion2
|
||||
M: Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
# CONFIG_MUSICPAL=n
|
||||
# CONFIG_MPS3R=n
|
||||
# CONFIG_MUSCA=n
|
||||
# CONFIG_CHEETAH=n
|
||||
# CONFIG_SX1=n
|
||||
# CONFIG_NSERIES=n
|
||||
# CONFIG_STELLARIS=n
|
||||
# CONFIG_STM32VLDISCOVERY=n
|
||||
# CONFIG_B_L475E_IOT01A=n
|
||||
|
@ -28,11 +26,6 @@
|
|||
# CONFIG_VERSATILE=n
|
||||
# CONFIG_VEXPRESS=n
|
||||
# CONFIG_ZYNQ=n
|
||||
# CONFIG_MAINSTONE=n
|
||||
# CONFIG_GUMSTIX=n
|
||||
# CONFIG_SPITZ=n
|
||||
# CONFIG_TOSA=n
|
||||
# CONFIG_Z2=n
|
||||
# CONFIG_NPCM7XX=n
|
||||
# CONFIG_COLLIE=n
|
||||
# CONFIG_ASPEED_SOC=n
|
||||
|
|
|
@ -251,21 +251,6 @@ to correct issues, mostly regarding migration compatibility. These are
|
|||
no longer maintained and removing them will make the code easier to
|
||||
read and maintain. Use versions 3.0 and above as a replacement.
|
||||
|
||||
Arm machines ``akita``, ``borzoi``, ``cheetah``, ``connex``, ``mainstone``, ``n800``, ``n810``, ``spitz``, ``terrier``, ``tosa``, ``verdex``, ``z2`` (since 9.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
QEMU includes models of some machine types where the QEMU code that
|
||||
emulates their SoCs is very old and unmaintained. This code is now
|
||||
blocking our ability to move forward with various changes across
|
||||
the codebase, and over many years nobody has been interested in
|
||||
trying to modernise it. We don't expect any of these machines to have
|
||||
a large number of users, because they're all modelling hardware that
|
||||
has now passed away into history. We are therefore dropping support
|
||||
for all machine types using the PXA2xx and OMAP2 SoCs. We are also
|
||||
dropping the ``cheetah`` OMAP1 board, because we don't have any
|
||||
test images for it and don't know of anybody who does; the ``sx1``
|
||||
and ``sx1-v1`` OMAP1 machines remain supported for now.
|
||||
|
||||
PPC 405 ``ref405ep`` machine (since 9.1)
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
|
|
@ -998,6 +998,20 @@ The Nios II architecture was orphan.
|
|||
|
||||
The machine was unmaintained.
|
||||
|
||||
Arm machines ``akita``, ``borzoi``, ``cheetah``, ``connex``, ``mainstone``, ``n800``, ``n810``, ``spitz``, ``terrier``, ``tosa``, ``verdex``, ``z2`` (removed in 9.2)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
QEMU included models of some machine types where the QEMU code that
|
||||
emulates their SoCs was very old and unmaintained. This code was
|
||||
blocking our ability to move forward with various changes across
|
||||
the codebase, and over many years nobody has been interested in
|
||||
trying to modernise it. We don't expect any of these machines to have
|
||||
a large number of users, because they're all modelling hardware that
|
||||
has now passed away into history. We are therefore dropping support
|
||||
for all machine types using the PXA2xx and OMAP2 SoCs. We are also
|
||||
dropping the ``cheetah`` OMAP1 board, because we don't have any
|
||||
test images for it and don't know of anybody who does.
|
||||
|
||||
linux-user mode CPUs
|
||||
--------------------
|
||||
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
Gumstix Connex and Verdex (``connex``, ``verdex``)
|
||||
==================================================
|
||||
|
||||
These machines model the Gumstix Connex and Verdex boards.
|
||||
The Connex has a PXA255 CPU and the Verdex has a PXA270.
|
||||
|
||||
Implemented devices:
|
||||
|
||||
* NOR flash
|
||||
* SMC91C111 ethernet
|
||||
* Interrupt controller
|
||||
* DMA
|
||||
* Timer
|
||||
* GPIO
|
||||
* MMC/SD card
|
||||
* Fast infra-red communications port (FIR)
|
||||
* LCD controller
|
||||
* Synchronous serial ports (SPI)
|
||||
* PCMCIA interface
|
||||
* I2C
|
||||
* I2S
|
|
@ -1,25 +0,0 @@
|
|||
Intel Mainstone II board (``mainstone``)
|
||||
========================================
|
||||
|
||||
The ``mainstone`` board emulates the Intel Mainstone II development
|
||||
board, which uses a PXA270 CPU.
|
||||
|
||||
Emulated devices:
|
||||
|
||||
- Flash memory
|
||||
- Keypad
|
||||
- MMC controller
|
||||
- 91C111 ethernet
|
||||
- PIC
|
||||
- Timer
|
||||
- DMA
|
||||
- GPIO
|
||||
- FIR
|
||||
- Serial
|
||||
- LCD controller
|
||||
- SSP
|
||||
- USB controller
|
||||
- RTC
|
||||
- PCMCIA
|
||||
- I2C
|
||||
- I2S
|
|
@ -1,33 +0,0 @@
|
|||
Nokia N800 and N810 tablets (``n800``, ``n810``)
|
||||
================================================
|
||||
|
||||
Nokia N800 and N810 internet tablets (known also as RX-34 and RX-44 /
|
||||
48) emulation supports the following elements:
|
||||
|
||||
- Texas Instruments OMAP2420 System-on-chip (ARM1136 core)
|
||||
|
||||
- RAM and non-volatile OneNAND Flash memories
|
||||
|
||||
- Display connected to EPSON remote framebuffer chip and OMAP on-chip
|
||||
display controller and a LS041y3 MIPI DBI-C controller
|
||||
|
||||
- TI TSC2301 (in N800) and TI TSC2005 (in N810) touchscreen
|
||||
controllers driven through SPI bus
|
||||
|
||||
- National Semiconductor LM8323-controlled qwerty keyboard driven
|
||||
through |I2C| bus
|
||||
|
||||
- Secure Digital card connected to OMAP MMC/SD host
|
||||
|
||||
- Three OMAP on-chip UARTs and on-chip STI debugging console
|
||||
|
||||
- Mentor Graphics \"Inventra\" dual-role USB controller embedded in a
|
||||
TI TUSB6010 chip - only USB host mode is supported
|
||||
|
||||
- TI TMP105 temperature sensor driven through |I2C| bus
|
||||
|
||||
- TI TWL92230C power management companion with an RTC on
|
||||
|I2C| bus
|
||||
|
||||
- Nokia RETU and TAHVO multi-purpose chips with an RTC, connected
|
||||
through CBUS
|
|
@ -1,23 +0,0 @@
|
|||
Palm Tungsten|E PDA (``cheetah``)
|
||||
=================================
|
||||
|
||||
The Palm Tungsten|E PDA (codename \"Cheetah\") emulation includes the
|
||||
following elements:
|
||||
|
||||
- Texas Instruments OMAP310 System-on-chip (ARM925T core)
|
||||
|
||||
- ROM and RAM memories (ROM firmware image can be loaded with
|
||||
-option-rom)
|
||||
|
||||
- On-chip LCD controller
|
||||
|
||||
- On-chip Real Time Clock
|
||||
|
||||
- TI TSC2102i touchscreen controller / analog-digital converter /
|
||||
Audio CODEC, connected through MicroWire and |I2S| buses
|
||||
|
||||
- GPIO-connected matrix keypad
|
||||
|
||||
- Secure Digital card connected to OMAP MMC/SD host
|
||||
|
||||
- Three on-chip UARTs
|
|
@ -1,35 +0,0 @@
|
|||
Sharp XScale-based PDA models (``akita``, ``borzoi``, ``spitz``, ``terrier``, ``tosa``)
|
||||
=======================================================================================
|
||||
|
||||
The Sharp Zaurus are PDAs based on XScale, able to run Linux ('SL series').
|
||||
|
||||
The SL-6000 (\"Tosa\"), released in 2005, uses a PXA255 System-on-chip.
|
||||
|
||||
The SL-C3000 (\"Spitz\"), SL-C1000 (\"Akita\"), SL-C3100 (\"Borzoi\") and
|
||||
SL-C3200 (\"Terrier\") use a PXA270.
|
||||
|
||||
The clamshell PDA models emulation includes the following peripherals:
|
||||
|
||||
- Intel PXA255/PXA270 System-on-chip (ARMv5TE core)
|
||||
|
||||
- NAND Flash memory - not in \"Tosa\"
|
||||
|
||||
- IBM/Hitachi DSCM microdrive in a PXA PCMCIA slot - not in \"Akita\"
|
||||
|
||||
- On-chip OHCI USB controller - not in \"Tosa\"
|
||||
|
||||
- On-chip LCD controller
|
||||
|
||||
- On-chip Real Time Clock
|
||||
|
||||
- TI ADS7846 touchscreen controller on SSP bus
|
||||
|
||||
- Maxim MAX1111 analog-digital converter on |I2C| bus
|
||||
|
||||
- GPIO-connected keyboard controller and LEDs
|
||||
|
||||
- Secure Digital card connected to PXA MMC/SD host
|
||||
|
||||
- Three on-chip UARTs
|
||||
|
||||
- WM8750 audio CODEC on |I2C| and |I2S| buses
|
|
@ -91,17 +91,12 @@ undocumented; you can get a complete list by running
|
|||
arm/cubieboard
|
||||
arm/emcraft-sf2
|
||||
arm/musicpal
|
||||
arm/gumstix
|
||||
arm/mainstone
|
||||
arm/kzm
|
||||
arm/nseries
|
||||
arm/nrf
|
||||
arm/nuvoton
|
||||
arm/imx25-pdk
|
||||
arm/orangepi
|
||||
arm/palm
|
||||
arm/raspi
|
||||
arm/xscale
|
||||
arm/collie
|
||||
arm/sx1
|
||||
arm/stellaris
|
||||
|
|
|
@ -37,13 +37,6 @@ config ARM_VIRT
|
|||
select ACPI_CXL
|
||||
select ACPI_HMAT
|
||||
|
||||
config CHEETAH
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select OMAP
|
||||
select TSC210X
|
||||
|
||||
config CUBIEBOARD
|
||||
bool
|
||||
default y
|
||||
|
@ -101,14 +94,6 @@ config INTEGRATOR
|
|||
select PL181 # display
|
||||
select SMC91C111
|
||||
|
||||
config MAINSTONE
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select PXA2XX
|
||||
select PFLASH_CFI01
|
||||
select SMC91C111
|
||||
|
||||
config MPS3R
|
||||
bool
|
||||
default y
|
||||
|
@ -157,20 +142,6 @@ config OLIMEX_STM32_H405
|
|||
depends on TCG && ARM
|
||||
select STM32F405_SOC
|
||||
|
||||
config NSERIES
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select OMAP
|
||||
select TMP105 # temperature sensor
|
||||
select BLIZZARD # LCD/TV controller
|
||||
select ONENAND
|
||||
select TSC210X # touchscreen/sensors/audio
|
||||
select TSC2005 # touchscreen/sensors/keypad
|
||||
select LM832X # GPIO keyboard chip
|
||||
select TWL92230 # energy-management
|
||||
select TUSB6010
|
||||
|
||||
config OMAP
|
||||
bool
|
||||
select FRAMEBUFFER
|
||||
|
@ -181,56 +152,6 @@ config OMAP
|
|||
select SD
|
||||
select SERIAL
|
||||
|
||||
config PXA2XX
|
||||
bool
|
||||
select FRAMEBUFFER
|
||||
select I2C
|
||||
select SERIAL
|
||||
select SD
|
||||
select SSI
|
||||
select USB_OHCI_SYSBUS
|
||||
select PCMCIA
|
||||
|
||||
config GUMSTIX
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select PFLASH_CFI01
|
||||
select SMC91C111
|
||||
select PXA2XX
|
||||
|
||||
config TOSA
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select ZAURUS # scoop
|
||||
select MICRODRIVE
|
||||
select PXA2XX
|
||||
select LED
|
||||
|
||||
config SPITZ
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select ADS7846 # touch-screen controller
|
||||
select MAX111X # A/D converter
|
||||
select WM8750 # audio codec
|
||||
select MAX7310 # GPIO expander
|
||||
select ZAURUS # scoop
|
||||
select NAND # memory
|
||||
select ECC # Error-correcting for NAND
|
||||
select MICRODRIVE
|
||||
select PXA2XX
|
||||
|
||||
config Z2
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select PFLASH_CFI01
|
||||
select WM8750
|
||||
select PL011 # UART
|
||||
select PXA2XX
|
||||
|
||||
config REALVIEW
|
||||
bool
|
||||
default y
|
||||
|
@ -316,14 +237,15 @@ config STM32VLDISCOVERY
|
|||
|
||||
config STRONGARM
|
||||
bool
|
||||
select PXA2XX
|
||||
select PXA2XX_TIMER
|
||||
select SSI
|
||||
|
||||
config COLLIE
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select PFLASH_CFI01
|
||||
select ZAURUS # scoop
|
||||
select ZAURUS_SCOOP
|
||||
select STRONGARM
|
||||
|
||||
config SX1
|
||||
|
@ -685,11 +607,6 @@ config MSF2
|
|||
select SSI
|
||||
select UNIMP
|
||||
|
||||
config ZAURUS
|
||||
bool
|
||||
select NAND
|
||||
select ECC
|
||||
|
||||
config ARMSSE
|
||||
bool
|
||||
select ARM_V7M
|
||||
|
|
141
hw/arm/gumstix.c
141
hw/arm/gumstix.c
|
@ -1,141 +0,0 @@
|
|||
/*
|
||||
* Gumstix Platforms
|
||||
*
|
||||
* Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org>
|
||||
*
|
||||
* Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example usage:
|
||||
*
|
||||
* connex:
|
||||
* =======
|
||||
* create image:
|
||||
* # dd of=flash bs=1k count=16k if=/dev/zero
|
||||
* # dd of=flash bs=1k conv=notrunc if=u-boot.bin
|
||||
* # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
|
||||
* start it:
|
||||
* # qemu-system-arm -M connex -pflash flash -monitor null -nographic
|
||||
*
|
||||
* verdex:
|
||||
* =======
|
||||
* create image:
|
||||
* # dd of=flash bs=1k count=32k if=/dev/zero
|
||||
* # dd of=flash bs=1k conv=notrunc if=u-boot.bin
|
||||
* # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
|
||||
* # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage
|
||||
* start it:
|
||||
* # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/net/smc91c111.h"
|
||||
#include "hw/boards.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
||||
#define CONNEX_FLASH_SIZE (16 * MiB)
|
||||
#define CONNEX_RAM_SIZE (64 * MiB)
|
||||
|
||||
#define VERDEX_FLASH_SIZE (32 * MiB)
|
||||
#define VERDEX_RAM_SIZE (256 * MiB)
|
||||
|
||||
#define FLASH_SECTOR_SIZE (128 * KiB)
|
||||
|
||||
static void connex_init(MachineState *machine)
|
||||
{
|
||||
PXA2xxState *cpu;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
cpu = pxa255_init(CONNEX_RAM_SIZE);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
if (!dinfo && !qtest_enabled()) {
|
||||
error_report("A flash image must be given with the "
|
||||
"'pflash' parameter");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Numonyx RC28F128J3F75 */
|
||||
pflash_cfi01_register(0x00000000, "connext.rom", CONNEX_FLASH_SIZE,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
FLASH_SECTOR_SIZE, 2, 0, 0, 0, 0, 0);
|
||||
|
||||
/* Interrupt line of NIC is connected to GPIO line 36 */
|
||||
smc91c111_init(0x04000300, qdev_get_gpio_in(cpu->gpio, 36));
|
||||
}
|
||||
|
||||
static void verdex_init(MachineState *machine)
|
||||
{
|
||||
PXA2xxState *cpu;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
cpu = pxa270_init(VERDEX_RAM_SIZE, machine->cpu_type);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
if (!dinfo && !qtest_enabled()) {
|
||||
error_report("A flash image must be given with the "
|
||||
"'pflash' parameter");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Micron RC28F256P30TFA */
|
||||
pflash_cfi01_register(0x00000000, "verdex.rom", VERDEX_FLASH_SIZE,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
FLASH_SECTOR_SIZE, 2, 0, 0, 0, 0, 0);
|
||||
|
||||
/* Interrupt line of NIC is connected to GPIO line 99 */
|
||||
smc91c111_init(0x04000300, qdev_get_gpio_in(cpu->gpio, 99));
|
||||
}
|
||||
|
||||
static void connex_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Gumstix Connex (PXA255)";
|
||||
mc->init = connex_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
}
|
||||
|
||||
static const TypeInfo connex_type = {
|
||||
.name = MACHINE_TYPE_NAME("connex"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = connex_class_init,
|
||||
};
|
||||
|
||||
static void verdex_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Gumstix Verdex Pro XL6P COMs (PXA270)";
|
||||
mc->init = verdex_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
|
||||
}
|
||||
|
||||
static const TypeInfo verdex_type = {
|
||||
.name = MACHINE_TYPE_NAME("verdex"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = verdex_class_init,
|
||||
};
|
||||
|
||||
static void gumstix_machine_init(void)
|
||||
{
|
||||
type_register_static(&connex_type);
|
||||
type_register_static(&verdex_type);
|
||||
}
|
||||
|
||||
type_init(gumstix_machine_init)
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* PXA270-based Intel Mainstone platforms.
|
||||
*
|
||||
* Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
|
||||
* <akuster@mvista.com>
|
||||
*
|
||||
* Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/net/smc91c111.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
/* Device addresses */
|
||||
#define MST_FPGA_PHYS 0x08000000
|
||||
#define MST_ETH_PHYS 0x10000300
|
||||
#define MST_FLASH_0 0x00000000
|
||||
#define MST_FLASH_1 0x04000000
|
||||
|
||||
/* IRQ definitions */
|
||||
#define MMC_IRQ 0
|
||||
#define USIM_IRQ 1
|
||||
#define USBC_IRQ 2
|
||||
#define ETHERNET_IRQ 3
|
||||
#define AC97_IRQ 4
|
||||
#define PEN_IRQ 5
|
||||
#define MSINS_IRQ 6
|
||||
#define EXBRD_IRQ 7
|
||||
#define S0_CD_IRQ 9
|
||||
#define S0_STSCHG_IRQ 10
|
||||
#define S0_IRQ 11
|
||||
#define S1_CD_IRQ 13
|
||||
#define S1_STSCHG_IRQ 14
|
||||
#define S1_IRQ 15
|
||||
|
||||
static const struct keymap map[0xE0] = {
|
||||
[0 ... 0xDF] = { -1, -1 },
|
||||
[0x1e] = {0,0}, /* a */
|
||||
[0x30] = {0,1}, /* b */
|
||||
[0x2e] = {0,2}, /* c */
|
||||
[0x20] = {0,3}, /* d */
|
||||
[0x12] = {0,4}, /* e */
|
||||
[0x21] = {0,5}, /* f */
|
||||
[0x22] = {1,0}, /* g */
|
||||
[0x23] = {1,1}, /* h */
|
||||
[0x17] = {1,2}, /* i */
|
||||
[0x24] = {1,3}, /* j */
|
||||
[0x25] = {1,4}, /* k */
|
||||
[0x26] = {1,5}, /* l */
|
||||
[0x32] = {2,0}, /* m */
|
||||
[0x31] = {2,1}, /* n */
|
||||
[0x18] = {2,2}, /* o */
|
||||
[0x19] = {2,3}, /* p */
|
||||
[0x10] = {2,4}, /* q */
|
||||
[0x13] = {2,5}, /* r */
|
||||
[0x1f] = {3,0}, /* s */
|
||||
[0x14] = {3,1}, /* t */
|
||||
[0x16] = {3,2}, /* u */
|
||||
[0x2f] = {3,3}, /* v */
|
||||
[0x11] = {3,4}, /* w */
|
||||
[0x2d] = {3,5}, /* x */
|
||||
[0x34] = {4,0}, /* . */
|
||||
[0x15] = {4,2}, /* y */
|
||||
[0x2c] = {4,3}, /* z */
|
||||
[0x35] = {4,4}, /* / */
|
||||
[0xc7] = {5,0}, /* Home */
|
||||
[0x2a] = {5,1}, /* shift */
|
||||
/*
|
||||
* There are two matrix positions which map to space,
|
||||
* but QEMU can only use one of them for the reverse
|
||||
* mapping, so simply use the second one.
|
||||
*/
|
||||
/* [0x39] = {5,2}, space */
|
||||
[0x39] = {5,3}, /* space */
|
||||
/*
|
||||
* Matrix position {5,4} and other keys are missing here.
|
||||
* TODO: Compare with Linux code and test real hardware.
|
||||
*/
|
||||
[0x1c] = {5,4}, /* enter */
|
||||
[0x0e] = {5,5}, /* backspace */
|
||||
[0xc8] = {6,0}, /* up */
|
||||
[0xd0] = {6,1}, /* down */
|
||||
[0xcb] = {6,2}, /* left */
|
||||
[0xcd] = {6,3}, /* right */
|
||||
};
|
||||
|
||||
enum mainstone_model_e { mainstone };
|
||||
|
||||
#define MAINSTONE_RAM_SIZE (64 * MiB)
|
||||
#define MAINSTONE_ROM_SIZE (8 * MiB)
|
||||
#define MAINSTONE_FLASH_SIZE (32 * MiB)
|
||||
|
||||
static struct arm_boot_info mainstone_binfo = {
|
||||
.loader_start = PXA2XX_SDRAM_BASE,
|
||||
.ram_size = MAINSTONE_RAM_SIZE,
|
||||
};
|
||||
|
||||
#define FLASH_SECTOR_SIZE (256 * KiB)
|
||||
|
||||
static void mainstone_common_init(MachineState *machine,
|
||||
enum mainstone_model_e model, int arm_id)
|
||||
{
|
||||
hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
|
||||
PXA2xxState *mpu;
|
||||
DeviceState *mst_irq;
|
||||
DriveInfo *dinfo;
|
||||
int i;
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
|
||||
/* Setup CPU & memory */
|
||||
mpu = pxa270_init(mainstone_binfo.ram_size, machine->cpu_type);
|
||||
memory_region_init_rom(rom, NULL, "mainstone.rom", MAINSTONE_ROM_SIZE,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), 0x00000000, rom);
|
||||
|
||||
/* There are two 32MiB flash devices on the board */
|
||||
for (i = 0; i < 2; i ++) {
|
||||
dinfo = drive_get(IF_PFLASH, 0, i);
|
||||
pflash_cfi01_register(mainstone_flash_base[i],
|
||||
i ? "mainstone.flash1" : "mainstone.flash0",
|
||||
MAINSTONE_FLASH_SIZE,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
FLASH_SECTOR_SIZE, 4, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS,
|
||||
qdev_get_gpio_in(mpu->gpio, 0));
|
||||
|
||||
/* setup keypad */
|
||||
pxa27x_register_keypad(mpu->kp, map, 0xe0);
|
||||
|
||||
/* MMC/SD host */
|
||||
pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ));
|
||||
|
||||
pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0],
|
||||
qdev_get_gpio_in(mst_irq, S0_IRQ),
|
||||
qdev_get_gpio_in(mst_irq, S0_CD_IRQ));
|
||||
pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1],
|
||||
qdev_get_gpio_in(mst_irq, S1_IRQ),
|
||||
qdev_get_gpio_in(mst_irq, S1_CD_IRQ));
|
||||
|
||||
smc91c111_init(MST_ETH_PHYS, qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
|
||||
|
||||
mainstone_binfo.board_id = arm_id;
|
||||
arm_load_kernel(mpu->cpu, machine, &mainstone_binfo);
|
||||
}
|
||||
|
||||
static void mainstone_init(MachineState *machine)
|
||||
{
|
||||
mainstone_common_init(machine, mainstone, 0x196);
|
||||
}
|
||||
|
||||
static void mainstone2_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "Mainstone II (PXA27x)";
|
||||
mc->init = mainstone_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("mainstone", mainstone2_machine_init)
|
|
@ -6,14 +6,12 @@ arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c'))
|
|||
arm_ss.add(when: 'CONFIG_EMCRAFT_SF2', if_true: files('msf2-som.c'))
|
||||
arm_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c'))
|
||||
arm_ss.add(when: 'CONFIG_INTEGRATOR', if_true: files('integratorcp.c'))
|
||||
arm_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mainstone.c'))
|
||||
arm_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c'))
|
||||
arm_ss.add(when: 'CONFIG_MPS3R', if_true: files('mps3r.c'))
|
||||
arm_ss.add(when: 'CONFIG_MUSICPAL', if_true: files('musicpal.c'))
|
||||
arm_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c'))
|
||||
arm_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c'))
|
||||
arm_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c'))
|
||||
arm_ss.add(when: 'CONFIG_NSERIES', if_true: files('nseries.c'))
|
||||
arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c'))
|
||||
arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
|
||||
arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
|
||||
|
@ -23,7 +21,6 @@ arm_ss.add(when: 'CONFIG_SABRELITE', if_true: files('sabrelite.c'))
|
|||
|
||||
arm_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m.c'))
|
||||
arm_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210.c'))
|
||||
arm_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx.c', 'pxa2xx_gpio.c', 'pxa2xx_pic.c'))
|
||||
arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic.c'))
|
||||
arm_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c'))
|
||||
arm_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
|
||||
|
@ -65,20 +62,14 @@ arm_ss.add(when: 'CONFIG_XEN', if_true: files(
|
|||
))
|
||||
|
||||
system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
|
||||
system_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c'))
|
||||
system_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c'))
|
||||
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
|
||||
system_ss.add(when: 'CONFIG_GUMSTIX', if_true: files('gumstix.c'))
|
||||
system_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c'))
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap2.c'))
|
||||
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
|
||||
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c'))
|
||||
system_ss.add(when: 'CONFIG_SPITZ', if_true: files('spitz.c'))
|
||||
system_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c'))
|
||||
system_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c'))
|
||||
system_ss.add(when: 'CONFIG_TOSA', if_true: files('tosa.c'))
|
||||
system_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c'))
|
||||
system_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c'))
|
||||
system_ss.add(when: 'CONFIG_Z2', if_true: files('z2.c'))
|
||||
|
||||
hw_arch += {'arm': arm_ss}
|
||||
|
|
1473
hw/arm/nseries.c
1473
hw/arm/nseries.c
File diff suppressed because it is too large
Load Diff
2715
hw/arm/omap2.c
2715
hw/arm/omap2.c
File diff suppressed because it is too large
Load Diff
324
hw/arm/palm.c
324
hw/arm/palm.c
|
@ -1,324 +0,0 @@
|
|||
/*
|
||||
* PalmOne's (TM) PDAs.
|
||||
*
|
||||
* Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "audio/audio.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/arm/omap.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "hw/input/tsc2xxx.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/loader.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
|
||||
static uint64_t static_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint32_t *val = (uint32_t *)opaque;
|
||||
uint32_t sizemask = 7 >> size;
|
||||
|
||||
return *val >> ((offset & sizemask) << 3);
|
||||
}
|
||||
|
||||
static void static_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
#ifdef SPY
|
||||
printf("%s: value %08lx written at " PA_FMT "\n",
|
||||
__func__, value, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const MemoryRegionOps static_ops = {
|
||||
.read = static_read,
|
||||
.write = static_write,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
/* Palm Tunsgten|E support */
|
||||
|
||||
/* Shared GPIOs */
|
||||
#define PALMTE_USBDETECT_GPIO 0
|
||||
#define PALMTE_USB_OR_DC_GPIO 1
|
||||
#define PALMTE_TSC_GPIO 4
|
||||
#define PALMTE_PINTDAV_GPIO 6
|
||||
#define PALMTE_MMC_WP_GPIO 8
|
||||
#define PALMTE_MMC_POWER_GPIO 9
|
||||
#define PALMTE_HDQ_GPIO 11
|
||||
#define PALMTE_HEADPHONES_GPIO 14
|
||||
#define PALMTE_SPEAKER_GPIO 15
|
||||
/* MPU private GPIOs */
|
||||
#define PALMTE_DC_GPIO 2
|
||||
#define PALMTE_MMC_SWITCH_GPIO 4
|
||||
#define PALMTE_MMC1_GPIO 6
|
||||
#define PALMTE_MMC2_GPIO 7
|
||||
#define PALMTE_MMC3_GPIO 11
|
||||
|
||||
static MouseTransformInfo palmte_pointercal = {
|
||||
.x = 320,
|
||||
.y = 320,
|
||||
.a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 },
|
||||
};
|
||||
|
||||
static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
|
||||
{
|
||||
uWireSlave *tsc;
|
||||
|
||||
tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
|
||||
|
||||
omap_uwire_attach(cpu->microwire, tsc, 0);
|
||||
omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
|
||||
|
||||
tsc210x_set_transform(tsc, &palmte_pointercal);
|
||||
}
|
||||
|
||||
static struct {
|
||||
int row;
|
||||
int column;
|
||||
} palmte_keymap[0x80] = {
|
||||
[0 ... 0x7f] = { -1, -1 },
|
||||
[0x3b] = { 0, 0 }, /* F1 -> Calendar */
|
||||
[0x3c] = { 1, 0 }, /* F2 -> Contacts */
|
||||
[0x3d] = { 2, 0 }, /* F3 -> Tasks List */
|
||||
[0x3e] = { 3, 0 }, /* F4 -> Note Pad */
|
||||
[0x01] = { 4, 0 }, /* Esc -> Power */
|
||||
[0x4b] = { 0, 1 }, /* Left */
|
||||
[0x50] = { 1, 1 }, /* Down */
|
||||
[0x48] = { 2, 1 }, /* Up */
|
||||
[0x4d] = { 3, 1 }, /* Right */
|
||||
[0x4c] = { 4, 1 }, /* Centre */
|
||||
[0x39] = { 4, 1 }, /* Spc -> Centre */
|
||||
};
|
||||
|
||||
static void palmte_button_event(void *opaque, int keycode)
|
||||
{
|
||||
struct omap_mpu_state_s *cpu = opaque;
|
||||
|
||||
if (palmte_keymap[keycode & 0x7f].row != -1)
|
||||
omap_mpuio_key(cpu->mpuio,
|
||||
palmte_keymap[keycode & 0x7f].row,
|
||||
palmte_keymap[keycode & 0x7f].column,
|
||||
!(keycode & 0x80));
|
||||
}
|
||||
|
||||
/*
|
||||
* Encapsulation of some GPIO line behaviour for the Palm board
|
||||
*
|
||||
* QEMU interface:
|
||||
* + unnamed GPIO inputs 0..6: for the various miscellaneous input lines
|
||||
*/
|
||||
|
||||
#define TYPE_PALM_MISC_GPIO "palm-misc-gpio"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PalmMiscGPIOState, PALM_MISC_GPIO)
|
||||
|
||||
struct PalmMiscGPIOState {
|
||||
SysBusDevice parent_obj;
|
||||
};
|
||||
|
||||
static void palmte_onoff_gpios(void *opaque, int line, int level)
|
||||
{
|
||||
switch (line) {
|
||||
case 0:
|
||||
printf("%s: current to MMC/SD card %sabled.\n",
|
||||
__func__, level ? "dis" : "en");
|
||||
break;
|
||||
case 1:
|
||||
printf("%s: internal speaker amplifier %s.\n",
|
||||
__func__, level ? "down" : "on");
|
||||
break;
|
||||
|
||||
/* These LCD & Audio output signals have not been identified yet. */
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
printf("%s: LCD GPIO%i %s.\n",
|
||||
__func__, line - 1, level ? "high" : "low");
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
printf("%s: Audio GPIO%i %s.\n",
|
||||
__func__, line - 4, level ? "high" : "low");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void palm_misc_gpio_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
qdev_init_gpio_in(dev, palmte_onoff_gpios, 7);
|
||||
}
|
||||
|
||||
static const TypeInfo palm_misc_gpio_info = {
|
||||
.name = TYPE_PALM_MISC_GPIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PalmMiscGPIOState),
|
||||
.instance_init = palm_misc_gpio_init,
|
||||
/*
|
||||
* No class init required: device has no internal state so does not
|
||||
* need to set up reset or vmstate, and has no realize method.
|
||||
*/
|
||||
};
|
||||
|
||||
static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
|
||||
{
|
||||
DeviceState *misc_gpio;
|
||||
|
||||
misc_gpio = sysbus_create_simple(TYPE_PALM_MISC_GPIO, -1, NULL);
|
||||
|
||||
omap_mmc_handlers(cpu->mmc,
|
||||
qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
|
||||
qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
|
||||
[PALMTE_MMC_SWITCH_GPIO]));
|
||||
|
||||
qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO,
|
||||
qdev_get_gpio_in(misc_gpio, 0));
|
||||
qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO,
|
||||
qdev_get_gpio_in(misc_gpio, 1));
|
||||
qdev_connect_gpio_out(cpu->gpio, 11, qdev_get_gpio_in(misc_gpio, 2));
|
||||
qdev_connect_gpio_out(cpu->gpio, 12, qdev_get_gpio_in(misc_gpio, 3));
|
||||
qdev_connect_gpio_out(cpu->gpio, 13, qdev_get_gpio_in(misc_gpio, 4));
|
||||
omap_mpuio_out_set(cpu->mpuio, 1, qdev_get_gpio_in(misc_gpio, 5));
|
||||
omap_mpuio_out_set(cpu->mpuio, 3, qdev_get_gpio_in(misc_gpio, 6));
|
||||
|
||||
/* Reset some inputs to initial state. */
|
||||
qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
|
||||
qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
|
||||
qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
|
||||
qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
|
||||
qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
|
||||
qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
|
||||
qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
|
||||
qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]);
|
||||
}
|
||||
|
||||
static struct arm_boot_info palmte_binfo = {
|
||||
.loader_start = OMAP_EMIFF_BASE,
|
||||
.ram_size = 0x02000000,
|
||||
.board_id = 0x331,
|
||||
};
|
||||
|
||||
static void palmte_init(MachineState *machine)
|
||||
{
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
struct omap_mpu_state_s *mpu;
|
||||
int flash_size = 0x00800000;
|
||||
static uint32_t cs0val = 0xffffffff;
|
||||
static uint32_t cs1val = 0x0000e1a0;
|
||||
static uint32_t cs2val = 0x0000e1a0;
|
||||
static uint32_t cs3val = 0xe1a0e1a0;
|
||||
int rom_size, rom_loaded = 0;
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
MemoryRegion *flash = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *cs = g_new(MemoryRegion, 4);
|
||||
|
||||
if (machine->ram_size != mc->default_ram_size) {
|
||||
char *sz = size_to_str(mc->default_ram_size);
|
||||
error_report("Invalid RAM size, should be %s", sz);
|
||||
g_free(sz);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memory_region_add_subregion(address_space_mem, OMAP_EMIFF_BASE,
|
||||
machine->ram);
|
||||
|
||||
mpu = omap310_mpu_init(machine->ram, machine->cpu_type);
|
||||
|
||||
/* External Flash (EMIFS) */
|
||||
memory_region_init_rom(flash, NULL, "palmte.flash", flash_size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
|
||||
|
||||
memory_region_init_io(&cs[0], NULL, &static_ops, &cs0val, "palmte-cs0",
|
||||
OMAP_CS0_SIZE - flash_size);
|
||||
memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size,
|
||||
&cs[0]);
|
||||
memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, "palmte-cs1",
|
||||
OMAP_CS1_SIZE);
|
||||
memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]);
|
||||
memory_region_init_io(&cs[2], NULL, &static_ops, &cs2val, "palmte-cs2",
|
||||
OMAP_CS2_SIZE);
|
||||
memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]);
|
||||
memory_region_init_io(&cs[3], NULL, &static_ops, &cs3val, "palmte-cs3",
|
||||
OMAP_CS3_SIZE);
|
||||
memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]);
|
||||
|
||||
palmte_microwire_setup(mpu);
|
||||
|
||||
qemu_add_kbd_event_handler(palmte_button_event, mpu);
|
||||
|
||||
palmte_gpio_setup(mpu);
|
||||
|
||||
/* Setup initial (reset) machine state */
|
||||
if (nb_option_roms) {
|
||||
rom_size = get_image_size(option_rom[0].name);
|
||||
if (rom_size > flash_size) {
|
||||
fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
|
||||
__func__, rom_size, flash_size);
|
||||
rom_size = 0;
|
||||
}
|
||||
if (rom_size > 0) {
|
||||
rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
|
||||
flash_size);
|
||||
rom_loaded = 1;
|
||||
}
|
||||
if (rom_size < 0) {
|
||||
fprintf(stderr, "%s: error loading '%s'\n",
|
||||
__func__, option_rom[0].name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rom_loaded && !machine->kernel_filename && !qtest_enabled()) {
|
||||
fprintf(stderr, "Kernel or ROM image must be specified\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Load the kernel. */
|
||||
arm_load_kernel(mpu->cpu, machine, &palmte_binfo);
|
||||
}
|
||||
|
||||
static void palmte_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)";
|
||||
mc->init = palmte_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t");
|
||||
mc->default_ram_size = 0x02000000;
|
||||
mc->default_ram_id = "omap1.dram";
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
|
||||
machine_add_audiodev_property(mc);
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("cheetah", palmte_machine_init)
|
||||
|
||||
static void palm_register_types(void)
|
||||
{
|
||||
type_register_static(&palm_misc_gpio_info);
|
||||
}
|
||||
|
||||
type_init(palm_register_types)
|
2393
hw/arm/pxa2xx.c
2393
hw/arm/pxa2xx.c
File diff suppressed because it is too large
Load Diff
|
@ -1,365 +0,0 @@
|
|||
/*
|
||||
* Intel XScale PXA255/270 GPIO controller emulation.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GPL.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define PXA2XX_GPIO_BANKS 4
|
||||
|
||||
#define TYPE_PXA2XX_GPIO "pxa2xx-gpio"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxGPIOInfo, PXA2XX_GPIO)
|
||||
|
||||
struct PXA2xxGPIOInfo {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq0, irq1, irqX;
|
||||
int lines;
|
||||
ARMCPU *cpu;
|
||||
|
||||
/* XXX: GNU C vectors are more suitable */
|
||||
uint32_t ilevel[PXA2XX_GPIO_BANKS];
|
||||
uint32_t olevel[PXA2XX_GPIO_BANKS];
|
||||
uint32_t dir[PXA2XX_GPIO_BANKS];
|
||||
uint32_t rising[PXA2XX_GPIO_BANKS];
|
||||
uint32_t falling[PXA2XX_GPIO_BANKS];
|
||||
uint32_t status[PXA2XX_GPIO_BANKS];
|
||||
uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
|
||||
|
||||
uint32_t prev_level[PXA2XX_GPIO_BANKS];
|
||||
qemu_irq handler[PXA2XX_GPIO_BANKS * 32];
|
||||
qemu_irq read_notify;
|
||||
};
|
||||
|
||||
static struct {
|
||||
enum {
|
||||
GPIO_NONE,
|
||||
GPLR,
|
||||
GPSR,
|
||||
GPCR,
|
||||
GPDR,
|
||||
GRER,
|
||||
GFER,
|
||||
GEDR,
|
||||
GAFR_L,
|
||||
GAFR_U,
|
||||
} reg;
|
||||
int bank;
|
||||
} pxa2xx_gpio_regs[0x200] = {
|
||||
[0 ... 0x1ff] = { GPIO_NONE, 0 },
|
||||
#define PXA2XX_REG(reg, a0, a1, a2, a3) \
|
||||
[a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 },
|
||||
|
||||
PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
|
||||
PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
|
||||
PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124)
|
||||
PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c)
|
||||
PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130)
|
||||
PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c)
|
||||
PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148)
|
||||
PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c)
|
||||
PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070)
|
||||
};
|
||||
|
||||
static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s)
|
||||
{
|
||||
if (s->status[0] & (1 << 0))
|
||||
qemu_irq_raise(s->irq0);
|
||||
else
|
||||
qemu_irq_lower(s->irq0);
|
||||
|
||||
if (s->status[0] & (1 << 1))
|
||||
qemu_irq_raise(s->irq1);
|
||||
else
|
||||
qemu_irq_lower(s->irq1);
|
||||
|
||||
if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
|
||||
qemu_irq_raise(s->irqX);
|
||||
else
|
||||
qemu_irq_lower(s->irqX);
|
||||
}
|
||||
|
||||
/* Bitmap of pins used as standby and sleep wake-up sources. */
|
||||
static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
|
||||
0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f,
|
||||
};
|
||||
|
||||
static void pxa2xx_gpio_set(void *opaque, int line, int level)
|
||||
{
|
||||
PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
|
||||
CPUState *cpu = CPU(s->cpu);
|
||||
int bank;
|
||||
uint32_t mask;
|
||||
|
||||
if (line >= s->lines) {
|
||||
printf("%s: No GPIO pin %i\n", __func__, line);
|
||||
return;
|
||||
}
|
||||
|
||||
bank = line >> 5;
|
||||
mask = 1U << (line & 31);
|
||||
|
||||
if (level) {
|
||||
s->status[bank] |= s->rising[bank] & mask &
|
||||
~s->ilevel[bank] & ~s->dir[bank];
|
||||
s->ilevel[bank] |= mask;
|
||||
} else {
|
||||
s->status[bank] |= s->falling[bank] & mask &
|
||||
s->ilevel[bank] & ~s->dir[bank];
|
||||
s->ilevel[bank] &= ~mask;
|
||||
}
|
||||
|
||||
if (s->status[bank] & mask)
|
||||
pxa2xx_gpio_irq_update(s);
|
||||
|
||||
/* Wake-up GPIOs */
|
||||
if (cpu->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) {
|
||||
cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) {
|
||||
uint32_t level, diff;
|
||||
int i, bit, line;
|
||||
for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
|
||||
level = s->olevel[i] & s->dir[i];
|
||||
|
||||
for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
|
||||
bit = ctz32(diff);
|
||||
line = bit + 32 * i;
|
||||
qemu_set_irq(s->handler[line], (level >> bit) & 1);
|
||||
}
|
||||
|
||||
s->prev_level[i] = level;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
|
||||
uint32_t ret;
|
||||
int bank;
|
||||
if (offset >= 0x200)
|
||||
return 0;
|
||||
|
||||
bank = pxa2xx_gpio_regs[offset].bank;
|
||||
switch (pxa2xx_gpio_regs[offset].reg) {
|
||||
case GPDR: /* GPIO Pin-Direction registers */
|
||||
return s->dir[bank];
|
||||
|
||||
case GPSR: /* GPIO Pin-Output Set registers */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pxa2xx GPIO: read from write only register GPSR\n");
|
||||
return 0;
|
||||
|
||||
case GPCR: /* GPIO Pin-Output Clear registers */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pxa2xx GPIO: read from write only register GPCR\n");
|
||||
return 0;
|
||||
|
||||
case GRER: /* GPIO Rising-Edge Detect Enable registers */
|
||||
return s->rising[bank];
|
||||
|
||||
case GFER: /* GPIO Falling-Edge Detect Enable registers */
|
||||
return s->falling[bank];
|
||||
|
||||
case GAFR_L: /* GPIO Alternate Function registers */
|
||||
return s->gafr[bank * 2];
|
||||
|
||||
case GAFR_U: /* GPIO Alternate Function registers */
|
||||
return s->gafr[bank * 2 + 1];
|
||||
|
||||
case GPLR: /* GPIO Pin-Level registers */
|
||||
ret = (s->olevel[bank] & s->dir[bank]) |
|
||||
(s->ilevel[bank] & ~s->dir[bank]);
|
||||
qemu_irq_raise(s->read_notify);
|
||||
return ret;
|
||||
|
||||
case GEDR: /* GPIO Edge Detect Status registers */
|
||||
return s->status[bank];
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_gpio_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
|
||||
int bank;
|
||||
if (offset >= 0x200)
|
||||
return;
|
||||
|
||||
bank = pxa2xx_gpio_regs[offset].bank;
|
||||
switch (pxa2xx_gpio_regs[offset].reg) {
|
||||
case GPDR: /* GPIO Pin-Direction registers */
|
||||
s->dir[bank] = value;
|
||||
pxa2xx_gpio_handler_update(s);
|
||||
break;
|
||||
|
||||
case GPSR: /* GPIO Pin-Output Set registers */
|
||||
s->olevel[bank] |= value;
|
||||
pxa2xx_gpio_handler_update(s);
|
||||
break;
|
||||
|
||||
case GPCR: /* GPIO Pin-Output Clear registers */
|
||||
s->olevel[bank] &= ~value;
|
||||
pxa2xx_gpio_handler_update(s);
|
||||
break;
|
||||
|
||||
case GRER: /* GPIO Rising-Edge Detect Enable registers */
|
||||
s->rising[bank] = value;
|
||||
break;
|
||||
|
||||
case GFER: /* GPIO Falling-Edge Detect Enable registers */
|
||||
s->falling[bank] = value;
|
||||
break;
|
||||
|
||||
case GAFR_L: /* GPIO Alternate Function registers */
|
||||
s->gafr[bank * 2] = value;
|
||||
break;
|
||||
|
||||
case GAFR_U: /* GPIO Alternate Function registers */
|
||||
s->gafr[bank * 2 + 1] = value;
|
||||
break;
|
||||
|
||||
case GEDR: /* GPIO Edge Detect Status registers */
|
||||
s->status[bank] &= ~value;
|
||||
pxa2xx_gpio_irq_update(s);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pxa_gpio_ops = {
|
||||
.read = pxa2xx_gpio_read,
|
||||
.write = pxa2xx_gpio_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
DeviceState *pxa2xx_gpio_init(hwaddr base,
|
||||
ARMCPU *cpu, DeviceState *pic, int lines)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new(TYPE_PXA2XX_GPIO);
|
||||
qdev_prop_set_int32(dev, "lines", lines);
|
||||
object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_abort);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
||||
qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1,
|
||||
qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2,
|
||||
qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X));
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void pxa2xx_gpio_initfn(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &pxa_gpio_ops,
|
||||
s, "pxa2xx-gpio", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq0);
|
||||
sysbus_init_irq(sbd, &s->irq1);
|
||||
sysbus_init_irq(sbd, &s->irqX);
|
||||
}
|
||||
|
||||
static void pxa2xx_gpio_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
|
||||
|
||||
qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines);
|
||||
qdev_init_gpio_out(dev, s->handler, s->lines);
|
||||
}
|
||||
|
||||
/*
|
||||
* Registers a callback to notify on GPLR reads. This normally
|
||||
* shouldn't be needed but it is used for the hack on Spitz machines.
|
||||
*/
|
||||
void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler)
|
||||
{
|
||||
PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
|
||||
|
||||
s->read_notify = handler;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
|
||||
.name = "pxa2xx-gpio",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2),
|
||||
VMSTATE_UINT32_ARRAY(prev_level, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static Property pxa2xx_gpio_properties[] = {
|
||||
DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
|
||||
DEFINE_PROP_LINK("cpu", PXA2xxGPIOInfo, cpu, TYPE_ARM_CPU, ARMCPU *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "PXA2xx GPIO controller";
|
||||
device_class_set_props(dc, pxa2xx_gpio_properties);
|
||||
dc->vmsd = &vmstate_pxa2xx_gpio_regs;
|
||||
dc->realize = pxa2xx_gpio_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo pxa2xx_gpio_info = {
|
||||
.name = TYPE_PXA2XX_GPIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PXA2xxGPIOInfo),
|
||||
.instance_init = pxa2xx_gpio_initfn,
|
||||
.class_init = pxa2xx_gpio_class_init,
|
||||
};
|
||||
|
||||
static void pxa2xx_gpio_register_types(void)
|
||||
{
|
||||
type_register_static(&pxa2xx_gpio_info);
|
||||
}
|
||||
|
||||
type_init(pxa2xx_gpio_register_types)
|
|
@ -1,359 +0,0 @@
|
|||
/*
|
||||
* Intel XScale PXA Programmable Interrupt Controller.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Copyright (c) 2006 Thorsten Zitterell
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GPL.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qom/object.h"
|
||||
#include "target/arm/cpregs.h"
|
||||
|
||||
#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */
|
||||
#define ICMR 0x04 /* Interrupt Controller Mask register */
|
||||
#define ICLR 0x08 /* Interrupt Controller Level register */
|
||||
#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */
|
||||
#define ICPR 0x10 /* Interrupt Controller Pending register */
|
||||
#define ICCR 0x14 /* Interrupt Controller Control register */
|
||||
#define ICHP 0x18 /* Interrupt Controller Highest Priority register */
|
||||
#define IPR0 0x1c /* Interrupt Controller Priority register 0 */
|
||||
#define IPR31 0x98 /* Interrupt Controller Priority register 31 */
|
||||
#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */
|
||||
#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */
|
||||
#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */
|
||||
#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */
|
||||
#define ICPR2 0xac /* Interrupt Controller Pending register 2 */
|
||||
#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */
|
||||
#define IPR39 0xcc /* Interrupt Controller Priority register 39 */
|
||||
|
||||
#define PXA2XX_PIC_SRCS 40
|
||||
|
||||
#define TYPE_PXA2XX_PIC "pxa2xx_pic"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxPICState, PXA2XX_PIC)
|
||||
|
||||
struct PXA2xxPICState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
MemoryRegion iomem;
|
||||
ARMCPU *cpu;
|
||||
uint32_t int_enabled[2];
|
||||
uint32_t int_pending[2];
|
||||
uint32_t is_fiq[2];
|
||||
uint32_t int_idle;
|
||||
uint32_t priority[PXA2XX_PIC_SRCS];
|
||||
};
|
||||
|
||||
static void pxa2xx_pic_update(void *opaque)
|
||||
{
|
||||
uint32_t mask[2];
|
||||
PXA2xxPICState *s = (PXA2xxPICState *) opaque;
|
||||
CPUState *cpu = CPU(s->cpu);
|
||||
|
||||
if (cpu->halted) {
|
||||
mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
|
||||
mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
|
||||
if (mask[0] || mask[1]) {
|
||||
cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
|
||||
}
|
||||
}
|
||||
|
||||
mask[0] = s->int_pending[0] & s->int_enabled[0];
|
||||
mask[1] = s->int_pending[1] & s->int_enabled[1];
|
||||
|
||||
if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) {
|
||||
cpu_interrupt(cpu, CPU_INTERRUPT_FIQ);
|
||||
} else {
|
||||
cpu_reset_interrupt(cpu, CPU_INTERRUPT_FIQ);
|
||||
}
|
||||
|
||||
if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) {
|
||||
cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: Here level means state of the signal on a pin, not
|
||||
* IRQ/FIQ distinction as in PXA Developer Manual. */
|
||||
static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
PXA2xxPICState *s = (PXA2xxPICState *) opaque;
|
||||
int int_set = (irq >= 32);
|
||||
irq &= 31;
|
||||
|
||||
if (level)
|
||||
s->int_pending[int_set] |= 1 << irq;
|
||||
else
|
||||
s->int_pending[int_set] &= ~(1 << irq);
|
||||
|
||||
pxa2xx_pic_update(opaque);
|
||||
}
|
||||
|
||||
static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
|
||||
int i, int_set, irq;
|
||||
uint32_t bit, mask[2];
|
||||
uint32_t ichp = 0x003f003f; /* Both IDs invalid */
|
||||
|
||||
mask[0] = s->int_pending[0] & s->int_enabled[0];
|
||||
mask[1] = s->int_pending[1] & s->int_enabled[1];
|
||||
|
||||
for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
|
||||
irq = s->priority[i] & 0x3f;
|
||||
if ((s->priority[i] & (1U << 31)) && irq < PXA2XX_PIC_SRCS) {
|
||||
/* Source peripheral ID is valid. */
|
||||
bit = 1 << (irq & 31);
|
||||
int_set = (irq >= 32);
|
||||
|
||||
if (mask[int_set] & bit & s->is_fiq[int_set]) {
|
||||
/* FIQ asserted */
|
||||
ichp &= 0xffff0000;
|
||||
ichp |= (1 << 15) | irq;
|
||||
}
|
||||
|
||||
if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
|
||||
/* IRQ asserted */
|
||||
ichp &= 0x0000ffff;
|
||||
ichp |= (1U << 31) | (irq << 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ichp;
|
||||
}
|
||||
|
||||
static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PXA2xxPICState *s = (PXA2xxPICState *) opaque;
|
||||
|
||||
switch (offset) {
|
||||
case ICIP: /* IRQ Pending register */
|
||||
return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
|
||||
case ICIP2: /* IRQ Pending register 2 */
|
||||
return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
|
||||
case ICMR: /* Mask register */
|
||||
return s->int_enabled[0];
|
||||
case ICMR2: /* Mask register 2 */
|
||||
return s->int_enabled[1];
|
||||
case ICLR: /* Level register */
|
||||
return s->is_fiq[0];
|
||||
case ICLR2: /* Level register 2 */
|
||||
return s->is_fiq[1];
|
||||
case ICCR: /* Idle mask */
|
||||
return (s->int_idle == 0);
|
||||
case ICFP: /* FIQ Pending register */
|
||||
return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
|
||||
case ICFP2: /* FIQ Pending register 2 */
|
||||
return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
|
||||
case ICPR: /* Pending register */
|
||||
return s->int_pending[0];
|
||||
case ICPR2: /* Pending register 2 */
|
||||
return s->int_pending[1];
|
||||
case IPR0 ... IPR31:
|
||||
return s->priority[0 + ((offset - IPR0 ) >> 2)];
|
||||
case IPR32 ... IPR39:
|
||||
return s->priority[32 + ((offset - IPR32) >> 2)];
|
||||
case ICHP: /* Highest Priority register */
|
||||
return pxa2xx_pic_highest(s);
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pxa2xx_pic_mem_read: bad register offset 0x%" HWADDR_PRIx
|
||||
"\n", offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PXA2xxPICState *s = (PXA2xxPICState *) opaque;
|
||||
|
||||
switch (offset) {
|
||||
case ICMR: /* Mask register */
|
||||
s->int_enabled[0] = value;
|
||||
break;
|
||||
case ICMR2: /* Mask register 2 */
|
||||
s->int_enabled[1] = value;
|
||||
break;
|
||||
case ICLR: /* Level register */
|
||||
s->is_fiq[0] = value;
|
||||
break;
|
||||
case ICLR2: /* Level register 2 */
|
||||
s->is_fiq[1] = value;
|
||||
break;
|
||||
case ICCR: /* Idle mask */
|
||||
s->int_idle = (value & 1) ? 0 : ~0;
|
||||
break;
|
||||
case IPR0 ... IPR31:
|
||||
s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
|
||||
break;
|
||||
case IPR32 ... IPR39:
|
||||
s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pxa2xx_pic_mem_write: bad register offset 0x%"
|
||||
HWADDR_PRIx "\n", offset);
|
||||
return;
|
||||
}
|
||||
pxa2xx_pic_update(opaque);
|
||||
}
|
||||
|
||||
/* Interrupt Controller Coprocessor Space Register Mapping */
|
||||
static const int pxa2xx_cp_reg_map[0x10] = {
|
||||
[0x0 ... 0xf] = -1,
|
||||
[0x0] = ICIP,
|
||||
[0x1] = ICMR,
|
||||
[0x2] = ICLR,
|
||||
[0x3] = ICFP,
|
||||
[0x4] = ICPR,
|
||||
[0x5] = ICHP,
|
||||
[0x6] = ICIP2,
|
||||
[0x7] = ICMR2,
|
||||
[0x8] = ICLR2,
|
||||
[0x9] = ICFP2,
|
||||
[0xa] = ICPR2,
|
||||
};
|
||||
|
||||
static uint64_t pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
int offset = pxa2xx_cp_reg_map[ri->crn];
|
||||
return pxa2xx_pic_mem_read(ri->opaque, offset, 4);
|
||||
}
|
||||
|
||||
static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
int offset = pxa2xx_cp_reg_map[ri->crn];
|
||||
pxa2xx_pic_mem_write(ri->opaque, offset, value, 4);
|
||||
}
|
||||
|
||||
#define REGINFO_FOR_PIC_CP(NAME, CRN) \
|
||||
{ .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \
|
||||
.access = PL1_RW, .type = ARM_CP_IO, \
|
||||
.readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write }
|
||||
|
||||
static const ARMCPRegInfo pxa_pic_cp_reginfo[] = {
|
||||
REGINFO_FOR_PIC_CP("ICIP", 0),
|
||||
REGINFO_FOR_PIC_CP("ICMR", 1),
|
||||
REGINFO_FOR_PIC_CP("ICLR", 2),
|
||||
REGINFO_FOR_PIC_CP("ICFP", 3),
|
||||
REGINFO_FOR_PIC_CP("ICPR", 4),
|
||||
REGINFO_FOR_PIC_CP("ICHP", 5),
|
||||
REGINFO_FOR_PIC_CP("ICIP2", 6),
|
||||
REGINFO_FOR_PIC_CP("ICMR2", 7),
|
||||
REGINFO_FOR_PIC_CP("ICLR2", 8),
|
||||
REGINFO_FOR_PIC_CP("ICFP2", 9),
|
||||
REGINFO_FOR_PIC_CP("ICPR2", 0xa),
|
||||
};
|
||||
|
||||
static const MemoryRegionOps pxa2xx_pic_ops = {
|
||||
.read = pxa2xx_pic_mem_read,
|
||||
.write = pxa2xx_pic_mem_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int pxa2xx_pic_post_load(void *opaque, int version_id)
|
||||
{
|
||||
pxa2xx_pic_update(opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_pic_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PXA2xxPICState *s = PXA2XX_PIC(obj);
|
||||
|
||||
s->int_pending[0] = 0;
|
||||
s->int_pending[1] = 0;
|
||||
s->int_enabled[0] = 0;
|
||||
s->int_enabled[1] = 0;
|
||||
s->is_fiq[0] = 0;
|
||||
s->is_fiq[1] = 0;
|
||||
}
|
||||
|
||||
DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu)
|
||||
{
|
||||
DeviceState *dev = qdev_new(TYPE_PXA2XX_PIC);
|
||||
|
||||
object_property_set_link(OBJECT(dev), "arm-cpu",
|
||||
OBJECT(cpu), &error_abort);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void pxa2xx_pic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PXA2xxPICState *s = PXA2XX_PIC(dev);
|
||||
|
||||
qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS);
|
||||
|
||||
/* Enable IC memory-mapped registers access. */
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_pic_ops, s,
|
||||
"pxa2xx-pic", 0x00100000);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
|
||||
/* Enable IC coprocessor access. */
|
||||
define_arm_cp_regs_with_opaque(s->cpu, pxa_pic_cp_reginfo, s);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pxa2xx_pic_regs = {
|
||||
.name = "pxa2xx_pic",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.post_load = pxa2xx_pic_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
|
||||
VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2),
|
||||
VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2),
|
||||
VMSTATE_UINT32(int_idle, PXA2xxPICState),
|
||||
VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static Property pxa2xx_pic_properties[] = {
|
||||
DEFINE_PROP_LINK("arm-cpu", PXA2xxPICState, cpu,
|
||||
TYPE_ARM_CPU, ARMCPU *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pxa2xx_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
device_class_set_props(dc, pxa2xx_pic_properties);
|
||||
dc->realize = pxa2xx_pic_realize;
|
||||
dc->desc = "PXA2xx PIC";
|
||||
dc->vmsd = &vmstate_pxa2xx_pic_regs;
|
||||
rc->phases.hold = pxa2xx_pic_reset_hold;
|
||||
}
|
||||
|
||||
static const TypeInfo pxa2xx_pic_info = {
|
||||
.name = TYPE_PXA2XX_PIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PXA2xxPICState),
|
||||
.class_init = pxa2xx_pic_class_init,
|
||||
};
|
||||
|
||||
static void pxa2xx_pic_register_types(void)
|
||||
{
|
||||
type_register_static(&pxa2xx_pic_info);
|
||||
}
|
||||
|
||||
type_init(pxa2xx_pic_register_types)
|
1284
hw/arm/spitz.c
1284
hw/arm/spitz.c
File diff suppressed because it is too large
Load Diff
327
hw/arm/tosa.c
327
hw/arm/tosa.c
|
@ -1,327 +0,0 @@
|
|||
/* vim:set shiftwidth=4 ts=4 et: */
|
||||
/*
|
||||
* PXA255 Sharp Zaurus SL-6000 PDA platform
|
||||
*
|
||||
* Copyright (c) 2008 Dmitry Baryshkov
|
||||
*
|
||||
* Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "hw/arm/sharpsl.h"
|
||||
#include "hw/pcmcia.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/display/tc6393xb.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/led.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TOSA_RAM 0x04000000
|
||||
#define TOSA_ROM 0x00800000
|
||||
|
||||
#define TOSA_GPIO_USB_IN (5)
|
||||
#define TOSA_GPIO_nSD_DETECT (9)
|
||||
#define TOSA_GPIO_ON_RESET (19)
|
||||
#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */
|
||||
#define TOSA_GPIO_CF_CD (13)
|
||||
#define TOSA_GPIO_TC6393XB_INT (15)
|
||||
#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */
|
||||
|
||||
#define TOSA_SCOOP_GPIO_BASE 1
|
||||
#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2)
|
||||
#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3)
|
||||
#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4)
|
||||
|
||||
#define TOSA_SCOOP_JC_GPIO_BASE 1
|
||||
#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0)
|
||||
#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1)
|
||||
#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2)
|
||||
#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5)
|
||||
#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7)
|
||||
|
||||
#define DAC_BASE 0x4e
|
||||
#define DAC_CH1 0
|
||||
#define DAC_CH2 1
|
||||
|
||||
static void tosa_microdrive_attach(PXA2xxState *cpu)
|
||||
{
|
||||
PCMCIACardState *md;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
dinfo = drive_get(IF_IDE, 0, 0);
|
||||
if (!dinfo || dinfo->media_cd)
|
||||
return;
|
||||
md = dscm1xxxx_init(dinfo);
|
||||
pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encapsulation of some GPIO line behaviour for the Tosa board
|
||||
*
|
||||
* QEMU interface:
|
||||
* + named GPIO inputs "leds[0..3]": assert to light LEDs
|
||||
* + named GPIO input "reset": when asserted, resets the system
|
||||
*/
|
||||
|
||||
#define TYPE_TOSA_MISC_GPIO "tosa-misc-gpio"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(TosaMiscGPIOState, TOSA_MISC_GPIO)
|
||||
|
||||
struct TosaMiscGPIOState {
|
||||
SysBusDevice parent_obj;
|
||||
};
|
||||
|
||||
static void tosa_reset(void *opaque, int line, int level)
|
||||
{
|
||||
if (level) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void tosa_misc_gpio_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
qdev_init_gpio_in_named(dev, tosa_reset, "reset", 1);
|
||||
}
|
||||
|
||||
static void tosa_gpio_setup(PXA2xxState *cpu,
|
||||
DeviceState *scp0,
|
||||
DeviceState *scp1,
|
||||
TC6393xbState *tmio)
|
||||
{
|
||||
DeviceState *misc_gpio;
|
||||
LEDState *led[4];
|
||||
|
||||
misc_gpio = sysbus_create_simple(TYPE_TOSA_MISC_GPIO, -1, NULL);
|
||||
|
||||
/* MMC/SD host */
|
||||
pxa2xx_mmci_handlers(cpu->mmc,
|
||||
qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
|
||||
qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
|
||||
|
||||
/* Handle reset */
|
||||
qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET,
|
||||
qdev_get_gpio_in_named(misc_gpio, "reset", 0));
|
||||
|
||||
/* PCMCIA signals: card's IRQ and Card-Detect */
|
||||
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
|
||||
qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
|
||||
qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
|
||||
|
||||
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
|
||||
qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
|
||||
NULL);
|
||||
|
||||
led[0] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
|
||||
LED_COLOR_BLUE, "bluetooth");
|
||||
led[1] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
|
||||
LED_COLOR_GREEN, "note");
|
||||
led[2] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
|
||||
LED_COLOR_AMBER, "charger-error");
|
||||
led[3] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
|
||||
LED_COLOR_GREEN, "wlan");
|
||||
|
||||
qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED,
|
||||
qdev_get_gpio_in(DEVICE(led[0]), 0));
|
||||
qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED,
|
||||
qdev_get_gpio_in(DEVICE(led[1]), 0));
|
||||
qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED,
|
||||
qdev_get_gpio_in(DEVICE(led[2]), 0));
|
||||
qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED,
|
||||
qdev_get_gpio_in(DEVICE(led[3]), 0));
|
||||
|
||||
qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
|
||||
|
||||
/* UDC Vbus */
|
||||
qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN));
|
||||
}
|
||||
|
||||
static uint32_t tosa_ssp_tansfer(SSIPeripheral *dev, uint32_t value)
|
||||
{
|
||||
fprintf(stderr, "TG: %u %02x\n", value >> 5, value & 0x1f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tosa_ssp_realize(SSIPeripheral *dev, Error **errp)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
#define TYPE_TOSA_DAC "tosa_dac"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(TosaDACState, TOSA_DAC)
|
||||
|
||||
struct TosaDACState {
|
||||
I2CSlave parent_obj;
|
||||
|
||||
int len;
|
||||
char buf[3];
|
||||
};
|
||||
|
||||
static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
|
||||
{
|
||||
TosaDACState *s = TOSA_DAC(i2c);
|
||||
|
||||
s->buf[s->len] = data;
|
||||
if (s->len ++ > 2) {
|
||||
#ifdef VERBOSE
|
||||
fprintf(stderr, "%s: message too long (%i bytes)\n", __func__, s->len);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (s->len == 2) {
|
||||
fprintf(stderr, "dac: channel %d value 0x%02x\n",
|
||||
s->buf[0], s->buf[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
TosaDACState *s = TOSA_DAC(i2c);
|
||||
|
||||
s->len = 0;
|
||||
switch (event) {
|
||||
case I2C_START_SEND:
|
||||
break;
|
||||
case I2C_START_RECV:
|
||||
printf("%s: recv not supported!!!\n", __func__);
|
||||
break;
|
||||
case I2C_FINISH:
|
||||
#ifdef VERBOSE
|
||||
if (s->len < 2)
|
||||
printf("%s: message too short (%i bytes)\n", __func__, s->len);
|
||||
if (s->len > 2)
|
||||
printf("%s: message too long\n", __func__);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t tosa_dac_recv(I2CSlave *s)
|
||||
{
|
||||
printf("%s: recv not supported!!!\n", __func__);
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void tosa_tg_init(PXA2xxState *cpu)
|
||||
{
|
||||
I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
|
||||
i2c_slave_create_simple(bus, TYPE_TOSA_DAC, DAC_BASE);
|
||||
ssi_create_peripheral(cpu->ssp[1], "tosa-ssp");
|
||||
}
|
||||
|
||||
|
||||
static struct arm_boot_info tosa_binfo = {
|
||||
.loader_start = PXA2XX_SDRAM_BASE,
|
||||
.ram_size = 0x04000000,
|
||||
};
|
||||
|
||||
static void tosa_init(MachineState *machine)
|
||||
{
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
PXA2xxState *mpu;
|
||||
TC6393xbState *tmio;
|
||||
DeviceState *scp0, *scp1;
|
||||
|
||||
mpu = pxa255_init(tosa_binfo.ram_size);
|
||||
|
||||
memory_region_init_rom(rom, NULL, "tosa.rom", TOSA_ROM, &error_fatal);
|
||||
memory_region_add_subregion(address_space_mem, 0, rom);
|
||||
|
||||
tmio = tc6393xb_init(address_space_mem, 0x10000000,
|
||||
qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT));
|
||||
|
||||
scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
|
||||
scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
|
||||
|
||||
tosa_gpio_setup(mpu, scp0, scp1, tmio);
|
||||
|
||||
tosa_microdrive_attach(mpu);
|
||||
|
||||
tosa_tg_init(mpu);
|
||||
|
||||
tosa_binfo.board_id = 0x208;
|
||||
arm_load_kernel(mpu->cpu, machine, &tosa_binfo);
|
||||
sl_bootparam_write(SL_PXA_PARAM_BASE);
|
||||
}
|
||||
|
||||
static void tosapda_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)";
|
||||
mc->init = tosa_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("tosa", tosapda_machine_init)
|
||||
|
||||
static void tosa_dac_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
k->event = tosa_dac_event;
|
||||
k->recv = tosa_dac_recv;
|
||||
k->send = tosa_dac_send;
|
||||
}
|
||||
|
||||
static const TypeInfo tosa_dac_info = {
|
||||
.name = TYPE_TOSA_DAC,
|
||||
.parent = TYPE_I2C_SLAVE,
|
||||
.instance_size = sizeof(TosaDACState),
|
||||
.class_init = tosa_dac_class_init,
|
||||
};
|
||||
|
||||
static void tosa_ssp_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
|
||||
|
||||
k->realize = tosa_ssp_realize;
|
||||
k->transfer = tosa_ssp_tansfer;
|
||||
}
|
||||
|
||||
static const TypeInfo tosa_ssp_info = {
|
||||
.name = "tosa-ssp",
|
||||
.parent = TYPE_SSI_PERIPHERAL,
|
||||
.instance_size = sizeof(SSIPeripheral),
|
||||
.class_init = tosa_ssp_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo tosa_misc_gpio_info = {
|
||||
.name = TYPE_TOSA_MISC_GPIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(TosaMiscGPIOState),
|
||||
.instance_init = tosa_misc_gpio_init,
|
||||
/*
|
||||
* No class init required: device has no internal state so does not
|
||||
* need to set up reset or vmstate, and has no realize method.
|
||||
*/
|
||||
};
|
||||
|
||||
static void tosa_register_types(void)
|
||||
{
|
||||
type_register_static(&tosa_dac_info);
|
||||
type_register_static(&tosa_ssp_info);
|
||||
type_register_static(&tosa_misc_gpio_info);
|
||||
}
|
||||
|
||||
type_init(tosa_register_types)
|
|
@ -258,14 +258,23 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
|
|||
char *name = g_strdup_printf("gem%d", i);
|
||||
DeviceState *dev;
|
||||
MemoryRegion *mr;
|
||||
OrIRQState *or_irq;
|
||||
|
||||
object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i],
|
||||
TYPE_CADENCE_GEM);
|
||||
or_irq = &s->lpd.iou.gem_irq_orgate[i];
|
||||
object_initialize_child(OBJECT(s), "gem-irq-orgate[*]",
|
||||
or_irq, TYPE_OR_IRQ);
|
||||
dev = DEVICE(&s->lpd.iou.gem[i]);
|
||||
qemu_configure_nic_device(dev, true, NULL);
|
||||
object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
|
||||
object_property_set_int(OBJECT(dev), "num-priority-queues", 2,
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(or_irq),
|
||||
"num-lines", 2, &error_fatal);
|
||||
qdev_realize(DEVICE(or_irq), NULL, &error_fatal);
|
||||
qdev_connect_gpio_out(DEVICE(or_irq), 0, pic[irqs[i]]);
|
||||
|
||||
object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
|
||||
&error_abort);
|
||||
sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
@ -273,7 +282,8 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
|
|||
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
|
||||
memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
|
||||
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(or_irq), 0));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, qdev_get_gpio_in(DEVICE(or_irq), 1));
|
||||
g_free(name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,6 +394,8 @@ static void xlnx_zynqmp_init(Object *obj)
|
|||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
|
||||
object_initialize_child(obj, "gem[*]", &s->gem[i], TYPE_CADENCE_GEM);
|
||||
object_initialize_child(obj, "gem-irq-orgate[*]",
|
||||
&s->gem_irq_orgate[i], TYPE_OR_IRQ);
|
||||
}
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
|
||||
|
@ -625,12 +627,19 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->gem[i]), "num-priority-queues", 2,
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->gem_irq_orgate[i]),
|
||||
"num-lines", 2, &error_fatal);
|
||||
qdev_realize(DEVICE(&s->gem_irq_orgate[i]), NULL, &error_fatal);
|
||||
qdev_connect_gpio_out(DEVICE(&s->gem_irq_orgate[i]), 0, gic_spi[gem_intr[i]]);
|
||||
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0,
|
||||
gic_spi[gem_intr[i]]);
|
||||
qdev_get_gpio_in(DEVICE(&s->gem_irq_orgate[i]), 0));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 1,
|
||||
qdev_get_gpio_in(DEVICE(&s->gem_irq_orgate[i]), 1));
|
||||
}
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
|
||||
|
|
355
hw/arm/z2.c
355
hw/arm/z2.c
|
@ -1,355 +0,0 @@
|
|||
/*
|
||||
* PXA270-based Zipit Z2 device
|
||||
*
|
||||
* Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
*
|
||||
* Code is based on mainstone platform.
|
||||
*
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/audio/wm8750.h"
|
||||
#include "audio/audio.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qom/object.h"
|
||||
#include "qapi/error.h"
|
||||
#include "trace.h"
|
||||
|
||||
static const struct keymap map[0x100] = {
|
||||
[0 ... 0xff] = { -1, -1 },
|
||||
[0x3b] = {0, 0}, /* Option = F1 */
|
||||
[0xc8] = {0, 1}, /* Up */
|
||||
[0xd0] = {0, 2}, /* Down */
|
||||
[0xcb] = {0, 3}, /* Left */
|
||||
[0xcd] = {0, 4}, /* Right */
|
||||
[0xcf] = {0, 5}, /* End */
|
||||
[0x0d] = {0, 6}, /* KPPLUS */
|
||||
[0xc7] = {1, 0}, /* Home */
|
||||
[0x10] = {1, 1}, /* Q */
|
||||
[0x17] = {1, 2}, /* I */
|
||||
[0x22] = {1, 3}, /* G */
|
||||
[0x2d] = {1, 4}, /* X */
|
||||
[0x1c] = {1, 5}, /* Enter */
|
||||
[0x0c] = {1, 6}, /* KPMINUS */
|
||||
[0xc9] = {2, 0}, /* PageUp */
|
||||
[0x11] = {2, 1}, /* W */
|
||||
[0x18] = {2, 2}, /* O */
|
||||
[0x23] = {2, 3}, /* H */
|
||||
[0x2e] = {2, 4}, /* C */
|
||||
[0x38] = {2, 5}, /* LeftAlt */
|
||||
[0xd1] = {3, 0}, /* PageDown */
|
||||
[0x12] = {3, 1}, /* E */
|
||||
[0x19] = {3, 2}, /* P */
|
||||
[0x24] = {3, 3}, /* J */
|
||||
[0x2f] = {3, 4}, /* V */
|
||||
[0x2a] = {3, 5}, /* LeftShift */
|
||||
[0x01] = {4, 0}, /* Esc */
|
||||
[0x13] = {4, 1}, /* R */
|
||||
[0x1e] = {4, 2}, /* A */
|
||||
[0x25] = {4, 3}, /* K */
|
||||
[0x30] = {4, 4}, /* B */
|
||||
[0x1d] = {4, 5}, /* LeftCtrl */
|
||||
[0x0f] = {5, 0}, /* Tab */
|
||||
[0x14] = {5, 1}, /* T */
|
||||
[0x1f] = {5, 2}, /* S */
|
||||
[0x26] = {5, 3}, /* L */
|
||||
[0x31] = {5, 4}, /* N */
|
||||
[0x39] = {5, 5}, /* Space */
|
||||
[0x3c] = {6, 0}, /* Stop = F2 */
|
||||
[0x15] = {6, 1}, /* Y */
|
||||
[0x20] = {6, 2}, /* D */
|
||||
[0x0e] = {6, 3}, /* Backspace */
|
||||
[0x32] = {6, 4}, /* M */
|
||||
[0x33] = {6, 5}, /* Comma */
|
||||
[0x3d] = {7, 0}, /* Play = F3 */
|
||||
[0x16] = {7, 1}, /* U */
|
||||
[0x21] = {7, 2}, /* F */
|
||||
[0x2c] = {7, 3}, /* Z */
|
||||
[0x27] = {7, 4}, /* Semicolon */
|
||||
[0x34] = {7, 5}, /* Dot */
|
||||
};
|
||||
|
||||
#define Z2_RAM_SIZE 0x02000000
|
||||
#define Z2_FLASH_BASE 0x00000000
|
||||
#define Z2_FLASH_SIZE 0x00800000
|
||||
|
||||
static struct arm_boot_info z2_binfo = {
|
||||
.loader_start = PXA2XX_SDRAM_BASE,
|
||||
.ram_size = Z2_RAM_SIZE,
|
||||
};
|
||||
|
||||
#define Z2_GPIO_SD_DETECT 96
|
||||
#define Z2_GPIO_AC_IN 0
|
||||
#define Z2_GPIO_KEY_ON 1
|
||||
#define Z2_GPIO_LCD_CS 88
|
||||
|
||||
struct ZipitLCD {
|
||||
SSIPeripheral ssidev;
|
||||
int32_t selected;
|
||||
int32_t enabled;
|
||||
uint8_t buf[3];
|
||||
uint32_t cur_reg;
|
||||
int pos;
|
||||
};
|
||||
|
||||
#define TYPE_ZIPIT_LCD "zipit-lcd"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(ZipitLCD, ZIPIT_LCD)
|
||||
|
||||
static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
|
||||
{
|
||||
ZipitLCD *z = ZIPIT_LCD(dev);
|
||||
uint16_t val;
|
||||
|
||||
trace_z2_lcd_reg_update(z->cur_reg, z->buf[0], z->buf[1], z->buf[2], value);
|
||||
if (z->selected) {
|
||||
z->buf[z->pos] = value & 0xff;
|
||||
z->pos++;
|
||||
}
|
||||
if (z->pos == 3) {
|
||||
switch (z->buf[0]) {
|
||||
case 0x74:
|
||||
z->cur_reg = z->buf[2];
|
||||
break;
|
||||
case 0x76:
|
||||
val = z->buf[1] << 8 | z->buf[2];
|
||||
if (z->cur_reg == 0x22 && val == 0x0000) {
|
||||
z->enabled = 1;
|
||||
trace_z2_lcd_enable_disable_result("enabled");
|
||||
} else if (z->cur_reg == 0x10 && val == 0x0000) {
|
||||
z->enabled = 0;
|
||||
trace_z2_lcd_enable_disable_result("disabled");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
z->pos = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void z2_lcd_cs(void *opaque, int line, int level)
|
||||
{
|
||||
ZipitLCD *z2_lcd = opaque;
|
||||
z2_lcd->selected = !level;
|
||||
}
|
||||
|
||||
static void zipit_lcd_realize(SSIPeripheral *dev, Error **errp)
|
||||
{
|
||||
ZipitLCD *z = ZIPIT_LCD(dev);
|
||||
z->selected = 0;
|
||||
z->enabled = 0;
|
||||
z->pos = 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_zipit_lcd_state = {
|
||||
.name = "zipit-lcd",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_SSI_PERIPHERAL(ssidev, ZipitLCD),
|
||||
VMSTATE_INT32(selected, ZipitLCD),
|
||||
VMSTATE_INT32(enabled, ZipitLCD),
|
||||
VMSTATE_BUFFER(buf, ZipitLCD),
|
||||
VMSTATE_UINT32(cur_reg, ZipitLCD),
|
||||
VMSTATE_INT32(pos, ZipitLCD),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static void zipit_lcd_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
|
||||
|
||||
k->realize = zipit_lcd_realize;
|
||||
k->transfer = zipit_lcd_transfer;
|
||||
dc->vmsd = &vmstate_zipit_lcd_state;
|
||||
}
|
||||
|
||||
static const TypeInfo zipit_lcd_info = {
|
||||
.name = TYPE_ZIPIT_LCD,
|
||||
.parent = TYPE_SSI_PERIPHERAL,
|
||||
.instance_size = sizeof(ZipitLCD),
|
||||
.class_init = zipit_lcd_class_init,
|
||||
};
|
||||
|
||||
#define TYPE_AER915 "aer915"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(AER915State, AER915)
|
||||
|
||||
struct AER915State {
|
||||
I2CSlave parent_obj;
|
||||
|
||||
int len;
|
||||
uint8_t buf[3];
|
||||
};
|
||||
|
||||
static int aer915_send(I2CSlave *i2c, uint8_t data)
|
||||
{
|
||||
AER915State *s = AER915(i2c);
|
||||
|
||||
s->buf[s->len] = data;
|
||||
if (s->len++ > 2) {
|
||||
trace_z2_aer915_send_too_long(s->len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (s->len == 2) {
|
||||
trace_z2_aer915_send(s->buf[0], s->buf[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aer915_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
AER915State *s = AER915(i2c);
|
||||
|
||||
trace_z2_aer915_event(s->len, event);
|
||||
switch (event) {
|
||||
case I2C_START_SEND:
|
||||
s->len = 0;
|
||||
break;
|
||||
case I2C_START_RECV:
|
||||
break;
|
||||
case I2C_FINISH:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t aer915_recv(I2CSlave *slave)
|
||||
{
|
||||
AER915State *s = AER915(slave);
|
||||
int retval = 0x00;
|
||||
|
||||
switch (s->buf[0]) {
|
||||
/* Return hardcoded battery voltage,
|
||||
* 0xf0 means ~4.1V
|
||||
*/
|
||||
case 0x02:
|
||||
retval = 0xf0;
|
||||
break;
|
||||
/* Return 0x00 for other regs,
|
||||
* we don't know what they are for,
|
||||
* anyway they return 0x00 on real hardware.
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_aer915_state = {
|
||||
.name = "aer915",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_INT32(len, AER915State),
|
||||
VMSTATE_BUFFER(buf, AER915State),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static void aer915_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
k->event = aer915_event;
|
||||
k->recv = aer915_recv;
|
||||
k->send = aer915_send;
|
||||
dc->vmsd = &vmstate_aer915_state;
|
||||
}
|
||||
|
||||
static const TypeInfo aer915_info = {
|
||||
.name = TYPE_AER915,
|
||||
.parent = TYPE_I2C_SLAVE,
|
||||
.instance_size = sizeof(AER915State),
|
||||
.class_init = aer915_class_init,
|
||||
};
|
||||
|
||||
#define FLASH_SECTOR_SIZE (64 * KiB)
|
||||
|
||||
static void z2_init(MachineState *machine)
|
||||
{
|
||||
PXA2xxState *mpu;
|
||||
DriveInfo *dinfo;
|
||||
void *z2_lcd;
|
||||
I2CBus *bus;
|
||||
DeviceState *wm;
|
||||
I2CSlave *i2c_dev;
|
||||
|
||||
/* Setup CPU & memory */
|
||||
mpu = pxa270_init(z2_binfo.ram_size, machine->cpu_type);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
FLASH_SECTOR_SIZE, 4, 0, 0, 0, 0, 0);
|
||||
|
||||
/* setup keypad */
|
||||
pxa27x_register_keypad(mpu->kp, map, 0x100);
|
||||
|
||||
/* MMC/SD host */
|
||||
pxa2xx_mmci_handlers(mpu->mmc,
|
||||
NULL,
|
||||
qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT));
|
||||
|
||||
type_register_static(&zipit_lcd_info);
|
||||
type_register_static(&aer915_info);
|
||||
z2_lcd = ssi_create_peripheral(mpu->ssp[1], TYPE_ZIPIT_LCD);
|
||||
bus = pxa2xx_i2c_bus(mpu->i2c[0]);
|
||||
|
||||
i2c_slave_create_simple(bus, TYPE_AER915, 0x55);
|
||||
|
||||
i2c_dev = i2c_slave_new(TYPE_WM8750, 0x1b);
|
||||
wm = DEVICE(i2c_dev);
|
||||
|
||||
if (machine->audiodev) {
|
||||
qdev_prop_set_string(wm, "audiodev", machine->audiodev);
|
||||
}
|
||||
i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort);
|
||||
|
||||
mpu->i2s->opaque = wm;
|
||||
mpu->i2s->codec_out = wm8750_dac_dat;
|
||||
mpu->i2s->codec_in = wm8750_adc_dat;
|
||||
wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s);
|
||||
|
||||
qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS,
|
||||
qemu_allocate_irq(z2_lcd_cs, z2_lcd, 0));
|
||||
|
||||
z2_binfo.board_id = 0x6dd;
|
||||
arm_load_kernel(mpu->cpu, machine, &z2_binfo);
|
||||
}
|
||||
|
||||
static void z2_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "Zipit Z2 (PXA27x)";
|
||||
mc->init = z2_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
|
||||
machine_add_audiodev_property(mc);
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("z2", z2_machine_init)
|
|
@ -25,9 +25,6 @@ config PFLASH_CFI02
|
|||
config ECC
|
||||
bool
|
||||
|
||||
config ONENAND
|
||||
bool
|
||||
|
||||
config VIRTIO_BLK
|
||||
bool
|
||||
default y
|
||||
|
|
|
@ -266,7 +266,8 @@ static const FlashPartInfo known_devices[] = {
|
|||
{ INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
|
||||
{ INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024,
|
||||
ER_4K | ER_32K, 2) },
|
||||
ER_4K | ER_32K, 2),
|
||||
.sfdp_read = m25p80_sfdp_mt35xu01g },
|
||||
{ INFO_STACKED("mt35xu02gbba", 0x2c5b1c, 0x104100, 128 << 10, 2048,
|
||||
ER_4K | ER_32K, 4),
|
||||
.sfdp_read = m25p80_sfdp_mt35xu02g },
|
||||
|
|
|
@ -57,6 +57,43 @@ static const uint8_t sfdp_n25q256a[] = {
|
|||
};
|
||||
define_sfdp_read(n25q256a);
|
||||
|
||||
static const uint8_t sfdp_mt35xu01g[] = {
|
||||
0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff,
|
||||
0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff,
|
||||
0x84, 0x00, 0x01, 0x02, 0x80, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xe5, 0x20, 0x8a, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x11, 0xd8,
|
||||
0x0f, 0x52, 0x00, 0x00, 0x24, 0x5a, 0x99, 0x00,
|
||||
0x8b, 0x8e, 0x03, 0xe1, 0xac, 0x01, 0x27, 0x38,
|
||||
0x7a, 0x75, 0x7a, 0x75, 0xfb, 0xbd, 0xd5, 0x5c,
|
||||
0x00, 0x00, 0x70, 0xff, 0x81, 0xb0, 0x38, 0x36,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x43, 0x0e, 0xff, 0xff, 0x21, 0xdc, 0x5c, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
|
||||
define_sfdp_read(mt35xu01g);
|
||||
|
||||
static const uint8_t sfdp_mt35xu02g[] = {
|
||||
0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff,
|
||||
0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define M25P80_SFDP_MAX_SIZE (1 << 24)
|
||||
|
||||
uint8_t m25p80_sfdp_n25q256a(uint32_t addr);
|
||||
uint8_t m25p80_sfdp_mt35xu01g(uint32_t addr);
|
||||
uint8_t m25p80_sfdp_mt35xu02g(uint32_t addr);
|
||||
|
||||
uint8_t m25p80_sfdp_mx25l25635e(uint32_t addr);
|
||||
|
|
|
@ -8,7 +8,6 @@ system_ss.add(when: 'CONFIG_FDC', if_true: files('fdc.c'))
|
|||
system_ss.add(when: 'CONFIG_FDC_ISA', if_true: files('fdc-isa.c'))
|
||||
system_ss.add(when: 'CONFIG_FDC_SYSBUS', if_true: files('fdc-sysbus.c'))
|
||||
system_ss.add(when: 'CONFIG_NAND', if_true: files('nand.c'))
|
||||
system_ss.add(when: 'CONFIG_ONENAND', if_true: files('onenand.c'))
|
||||
system_ss.add(when: 'CONFIG_PFLASH_CFI01', if_true: files('pflash_cfi01.c'))
|
||||
system_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: files('pflash_cfi02.c'))
|
||||
system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c'))
|
||||
|
|
|
@ -1,872 +0,0 @@
|
|||
/*
|
||||
* OneNAND flash memories emulation.
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/memory.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
|
||||
#define PAGE_SHIFT 11
|
||||
|
||||
/* Fixed */
|
||||
#define BLOCK_SHIFT (PAGE_SHIFT + 6)
|
||||
|
||||
#define TYPE_ONE_NAND "onenand"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(OneNANDState, ONE_NAND)
|
||||
|
||||
struct OneNANDState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
struct {
|
||||
uint16_t man;
|
||||
uint16_t dev;
|
||||
uint16_t ver;
|
||||
} id;
|
||||
int shift;
|
||||
hwaddr base;
|
||||
qemu_irq intr;
|
||||
qemu_irq rdy;
|
||||
BlockBackend *blk;
|
||||
BlockBackend *blk_cur;
|
||||
uint8_t *image;
|
||||
uint8_t *otp;
|
||||
uint8_t *current;
|
||||
MemoryRegion ram;
|
||||
MemoryRegion mapped_ram;
|
||||
uint8_t current_direction;
|
||||
uint8_t *boot[2];
|
||||
uint8_t *data[2][2];
|
||||
MemoryRegion iomem;
|
||||
MemoryRegion container;
|
||||
int cycle;
|
||||
int otpmode;
|
||||
|
||||
uint16_t addr[8];
|
||||
uint16_t unladdr[8];
|
||||
int bufaddr;
|
||||
int count;
|
||||
uint16_t command;
|
||||
uint16_t config[2];
|
||||
uint16_t status;
|
||||
uint16_t intstatus;
|
||||
uint16_t wpstatus;
|
||||
|
||||
ECCState ecc;
|
||||
|
||||
int density_mask;
|
||||
int secs;
|
||||
int secs_cur;
|
||||
int blocks;
|
||||
uint8_t *blockwp;
|
||||
};
|
||||
|
||||
enum {
|
||||
ONEN_BUF_BLOCK = 0,
|
||||
ONEN_BUF_BLOCK2 = 1,
|
||||
ONEN_BUF_DEST_BLOCK = 2,
|
||||
ONEN_BUF_DEST_PAGE = 3,
|
||||
ONEN_BUF_PAGE = 7,
|
||||
};
|
||||
|
||||
enum {
|
||||
ONEN_ERR_CMD = 1 << 10,
|
||||
ONEN_ERR_ERASE = 1 << 11,
|
||||
ONEN_ERR_PROG = 1 << 12,
|
||||
ONEN_ERR_LOAD = 1 << 13,
|
||||
};
|
||||
|
||||
enum {
|
||||
ONEN_INT_RESET = 1 << 4,
|
||||
ONEN_INT_ERASE = 1 << 5,
|
||||
ONEN_INT_PROG = 1 << 6,
|
||||
ONEN_INT_LOAD = 1 << 7,
|
||||
ONEN_INT = 1 << 15,
|
||||
};
|
||||
|
||||
enum {
|
||||
ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
|
||||
ONEN_LOCK_LOCKED = 1 << 1,
|
||||
ONEN_LOCK_UNLOCKED = 1 << 2,
|
||||
};
|
||||
|
||||
static void onenand_mem_setup(OneNANDState *s)
|
||||
{
|
||||
/* XXX: We should use IO_MEM_ROMD but we broke it earlier...
|
||||
* Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
|
||||
* write boot commands. Also take note of the BWPS bit. */
|
||||
memory_region_init(&s->container, OBJECT(s), "onenand",
|
||||
0x10000 << s->shift);
|
||||
memory_region_add_subregion(&s->container, 0, &s->iomem);
|
||||
memory_region_init_alias(&s->mapped_ram, OBJECT(s), "onenand-mapped-ram",
|
||||
&s->ram, 0x0200 << s->shift,
|
||||
0xbe00 << s->shift);
|
||||
memory_region_add_subregion_overlap(&s->container,
|
||||
0x0200 << s->shift,
|
||||
&s->mapped_ram,
|
||||
1);
|
||||
}
|
||||
|
||||
static void onenand_intr_update(OneNANDState *s)
|
||||
{
|
||||
qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
|
||||
}
|
||||
|
||||
static int onenand_pre_save(void *opaque)
|
||||
{
|
||||
OneNANDState *s = opaque;
|
||||
if (s->current == s->otp) {
|
||||
s->current_direction = 1;
|
||||
} else if (s->current == s->image) {
|
||||
s->current_direction = 2;
|
||||
} else {
|
||||
s->current_direction = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int onenand_post_load(void *opaque, int version_id)
|
||||
{
|
||||
OneNANDState *s = opaque;
|
||||
switch (s->current_direction) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
s->current = s->otp;
|
||||
break;
|
||||
case 2:
|
||||
s->current = s->image;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
onenand_intr_update(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_onenand = {
|
||||
.name = "onenand",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = onenand_pre_save,
|
||||
.post_load = onenand_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT8(current_direction, OneNANDState),
|
||||
VMSTATE_INT32(cycle, OneNANDState),
|
||||
VMSTATE_INT32(otpmode, OneNANDState),
|
||||
VMSTATE_UINT16_ARRAY(addr, OneNANDState, 8),
|
||||
VMSTATE_UINT16_ARRAY(unladdr, OneNANDState, 8),
|
||||
VMSTATE_INT32(bufaddr, OneNANDState),
|
||||
VMSTATE_INT32(count, OneNANDState),
|
||||
VMSTATE_UINT16(command, OneNANDState),
|
||||
VMSTATE_UINT16_ARRAY(config, OneNANDState, 2),
|
||||
VMSTATE_UINT16(status, OneNANDState),
|
||||
VMSTATE_UINT16(intstatus, OneNANDState),
|
||||
VMSTATE_UINT16(wpstatus, OneNANDState),
|
||||
VMSTATE_INT32(secs_cur, OneNANDState),
|
||||
VMSTATE_PARTIAL_VBUFFER(blockwp, OneNANDState, blocks),
|
||||
VMSTATE_UINT8(ecc.cp, OneNANDState),
|
||||
VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
|
||||
VMSTATE_UINT16(ecc.count, OneNANDState),
|
||||
VMSTATE_BUFFER_POINTER_UNSAFE(otp, OneNANDState, 0,
|
||||
((64 + 2) << PAGE_SHIFT)),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
|
||||
static void onenand_reset(OneNANDState *s, int cold)
|
||||
{
|
||||
memset(&s->addr, 0, sizeof(s->addr));
|
||||
s->command = 0;
|
||||
s->count = 1;
|
||||
s->bufaddr = 0;
|
||||
s->config[0] = 0x40c0;
|
||||
s->config[1] = 0x0000;
|
||||
onenand_intr_update(s);
|
||||
qemu_irq_raise(s->rdy);
|
||||
s->status = 0x0000;
|
||||
s->intstatus = cold ? 0x8080 : 0x8010;
|
||||
s->unladdr[0] = 0;
|
||||
s->unladdr[1] = 0;
|
||||
s->wpstatus = 0x0002;
|
||||
s->cycle = 0;
|
||||
s->otpmode = 0;
|
||||
s->blk_cur = s->blk;
|
||||
s->current = s->image;
|
||||
s->secs_cur = s->secs;
|
||||
|
||||
if (cold) {
|
||||
/* Lock the whole flash */
|
||||
memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
|
||||
|
||||
if (s->blk_cur && blk_pread(s->blk_cur, 0, 8 << BDRV_SECTOR_BITS,
|
||||
s->boot[0], 0) < 0) {
|
||||
hw_error("%s: Loading the BootRAM failed.\n", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void onenand_system_reset(DeviceState *dev)
|
||||
{
|
||||
OneNANDState *s = ONE_NAND(dev);
|
||||
|
||||
onenand_reset(s, 1);
|
||||
}
|
||||
|
||||
static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
|
||||
void *dest)
|
||||
{
|
||||
assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
|
||||
assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
|
||||
if (s->blk_cur) {
|
||||
return blk_pread(s->blk_cur, sec << BDRV_SECTOR_BITS,
|
||||
secn << BDRV_SECTOR_BITS, dest, 0) < 0;
|
||||
} else if (sec + secn > s->secs_cur) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(dest, s->current + (sec << 9), secn << 9);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
|
||||
void *src)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (secn > 0) {
|
||||
uint32_t size = secn << BDRV_SECTOR_BITS;
|
||||
uint32_t offset = sec << BDRV_SECTOR_BITS;
|
||||
assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
|
||||
assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
|
||||
const uint8_t *sp = (const uint8_t *)src;
|
||||
uint8_t *dp = 0;
|
||||
if (s->blk_cur) {
|
||||
dp = g_malloc(size);
|
||||
if (!dp || blk_pread(s->blk_cur, offset, size, dp, 0) < 0) {
|
||||
result = 1;
|
||||
}
|
||||
} else {
|
||||
if (sec + secn > s->secs_cur) {
|
||||
result = 1;
|
||||
} else {
|
||||
dp = (uint8_t *)s->current + offset;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
dp[i] &= sp[i];
|
||||
}
|
||||
if (s->blk_cur) {
|
||||
result = blk_pwrite(s->blk_cur, offset, size, dp, 0) < 0;
|
||||
}
|
||||
}
|
||||
if (dp && s->blk_cur) {
|
||||
g_free(dp);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
|
||||
void *dest)
|
||||
{
|
||||
uint8_t buf[512];
|
||||
|
||||
if (s->blk_cur) {
|
||||
uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
|
||||
if (blk_pread(s->blk_cur, offset, BDRV_SECTOR_SIZE, buf, 0) < 0) {
|
||||
return 1;
|
||||
}
|
||||
memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
|
||||
} else if (sec + secn > s->secs_cur) {
|
||||
return 1;
|
||||
} else {
|
||||
memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
|
||||
void *src)
|
||||
{
|
||||
int result = 0;
|
||||
if (secn > 0) {
|
||||
const uint8_t *sp = (const uint8_t *)src;
|
||||
uint8_t *dp = 0, *dpp = 0;
|
||||
uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
|
||||
assert(UINT32_MAX >> BDRV_SECTOR_BITS > s->secs_cur + (sec >> 5));
|
||||
if (s->blk_cur) {
|
||||
dp = g_malloc(512);
|
||||
if (!dp
|
||||
|| blk_pread(s->blk_cur, offset, BDRV_SECTOR_SIZE, dp, 0) < 0) {
|
||||
result = 1;
|
||||
} else {
|
||||
dpp = dp + ((sec & 31) << 4);
|
||||
}
|
||||
} else {
|
||||
if (sec + secn > s->secs_cur) {
|
||||
result = 1;
|
||||
} else {
|
||||
dpp = s->current + (s->secs_cur << 9) + (sec << 4);
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < (secn << 4); i++) {
|
||||
dpp[i] &= sp[i];
|
||||
}
|
||||
if (s->blk_cur) {
|
||||
result = blk_pwrite(s->blk_cur, offset, BDRV_SECTOR_SIZE, dp,
|
||||
0) < 0;
|
||||
}
|
||||
}
|
||||
g_free(dp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int onenand_erase(OneNANDState *s, int sec, int num)
|
||||
{
|
||||
uint8_t *blankbuf, *tmpbuf;
|
||||
|
||||
blankbuf = g_malloc(512);
|
||||
tmpbuf = g_malloc(512);
|
||||
memset(blankbuf, 0xff, 512);
|
||||
for (; num > 0; num--, sec++) {
|
||||
if (s->blk_cur) {
|
||||
int erasesec = s->secs_cur + (sec >> 5);
|
||||
if (blk_pwrite(s->blk_cur, sec << BDRV_SECTOR_BITS,
|
||||
BDRV_SECTOR_SIZE, blankbuf, 0) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
if (blk_pread(s->blk_cur, erasesec << BDRV_SECTOR_BITS,
|
||||
BDRV_SECTOR_SIZE, tmpbuf, 0) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
|
||||
if (blk_pwrite(s->blk_cur, erasesec << BDRV_SECTOR_BITS,
|
||||
BDRV_SECTOR_SIZE, tmpbuf, 0) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (sec + 1 > s->secs_cur) {
|
||||
goto fail;
|
||||
}
|
||||
memcpy(s->current + (sec << 9), blankbuf, 512);
|
||||
memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
|
||||
blankbuf, 1 << 4);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(tmpbuf);
|
||||
g_free(blankbuf);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
g_free(tmpbuf);
|
||||
g_free(blankbuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void onenand_command(OneNANDState *s)
|
||||
{
|
||||
int b;
|
||||
int sec;
|
||||
void *buf;
|
||||
#define SETADDR(block, page) \
|
||||
sec = (s->addr[page] & 3) + \
|
||||
((((s->addr[page] >> 2) & 0x3f) + \
|
||||
(((s->addr[block] & 0xfff) | \
|
||||
(s->addr[block] >> 15 ? s->density_mask : 0)) \
|
||||
<< 6)) \
|
||||
<< (PAGE_SHIFT - 9));
|
||||
#define SETBUF_M() \
|
||||
buf = (s->bufaddr & 8) ? s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0]; \
|
||||
buf += (s->bufaddr & 3) << 9;
|
||||
#define SETBUF_S() \
|
||||
buf = (s->bufaddr & 8) ? \
|
||||
s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1]; \
|
||||
buf += (s->bufaddr & 3) << 4;
|
||||
|
||||
switch (s->command) {
|
||||
case 0x00: /* Load single/multiple sector data unit into buffer */
|
||||
SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
|
||||
|
||||
SETBUF_M()
|
||||
if (onenand_load_main(s, sec, s->count, buf))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
|
||||
|
||||
#if 0
|
||||
SETBUF_S()
|
||||
if (onenand_load_spare(s, sec, s->count, buf))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
|
||||
#endif
|
||||
|
||||
/* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
|
||||
* or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
|
||||
* then we need two split the read/write into two chunks.
|
||||
*/
|
||||
s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
|
||||
break;
|
||||
case 0x13: /* Load single/multiple spare sector into buffer */
|
||||
SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
|
||||
|
||||
SETBUF_S()
|
||||
if (onenand_load_spare(s, sec, s->count, buf))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
|
||||
|
||||
/* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
|
||||
* or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
|
||||
* then we need two split the read/write into two chunks.
|
||||
*/
|
||||
s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
|
||||
break;
|
||||
case 0x80: /* Program single/multiple sector data unit from buffer */
|
||||
SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
|
||||
|
||||
SETBUF_M()
|
||||
if (onenand_prog_main(s, sec, s->count, buf))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
|
||||
|
||||
#if 0
|
||||
SETBUF_S()
|
||||
if (onenand_prog_spare(s, sec, s->count, buf))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
|
||||
#endif
|
||||
|
||||
/* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
|
||||
* or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
|
||||
* then we need two split the read/write into two chunks.
|
||||
*/
|
||||
s->intstatus |= ONEN_INT | ONEN_INT_PROG;
|
||||
break;
|
||||
case 0x1a: /* Program single/multiple spare area sector from buffer */
|
||||
SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
|
||||
|
||||
SETBUF_S()
|
||||
if (onenand_prog_spare(s, sec, s->count, buf))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
|
||||
|
||||
/* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
|
||||
* or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
|
||||
* then we need two split the read/write into two chunks.
|
||||
*/
|
||||
s->intstatus |= ONEN_INT | ONEN_INT_PROG;
|
||||
break;
|
||||
case 0x1b: /* Copy-back program */
|
||||
SETBUF_S()
|
||||
|
||||
SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
|
||||
if (onenand_load_main(s, sec, s->count, buf))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
|
||||
|
||||
SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
|
||||
if (onenand_prog_main(s, sec, s->count, buf))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
|
||||
|
||||
/* TODO: spare areas */
|
||||
|
||||
s->intstatus |= ONEN_INT | ONEN_INT_PROG;
|
||||
break;
|
||||
|
||||
case 0x23: /* Unlock NAND array block(s) */
|
||||
s->intstatus |= ONEN_INT;
|
||||
|
||||
/* XXX the previous (?) area should be locked automatically */
|
||||
for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
|
||||
if (b >= s->blocks) {
|
||||
s->status |= ONEN_ERR_CMD;
|
||||
break;
|
||||
}
|
||||
if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
|
||||
break;
|
||||
|
||||
s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
|
||||
}
|
||||
break;
|
||||
case 0x27: /* Unlock All NAND array blocks */
|
||||
s->intstatus |= ONEN_INT;
|
||||
|
||||
for (b = 0; b < s->blocks; b ++) {
|
||||
if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
|
||||
break;
|
||||
|
||||
s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2a: /* Lock NAND array block(s) */
|
||||
s->intstatus |= ONEN_INT;
|
||||
|
||||
for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
|
||||
if (b >= s->blocks) {
|
||||
s->status |= ONEN_ERR_CMD;
|
||||
break;
|
||||
}
|
||||
if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
|
||||
break;
|
||||
|
||||
s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
|
||||
}
|
||||
break;
|
||||
case 0x2c: /* Lock-tight NAND array block(s) */
|
||||
s->intstatus |= ONEN_INT;
|
||||
|
||||
for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
|
||||
if (b >= s->blocks) {
|
||||
s->status |= ONEN_ERR_CMD;
|
||||
break;
|
||||
}
|
||||
if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
|
||||
continue;
|
||||
|
||||
s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x71: /* Erase-Verify-Read */
|
||||
s->intstatus |= ONEN_INT;
|
||||
break;
|
||||
case 0x95: /* Multi-block erase */
|
||||
qemu_irq_pulse(s->intr);
|
||||
/* Fall through. */
|
||||
case 0x94: /* Block erase */
|
||||
sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
|
||||
(s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
|
||||
<< (BLOCK_SHIFT - 9);
|
||||
if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
|
||||
s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
|
||||
|
||||
s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
|
||||
break;
|
||||
case 0xb0: /* Erase suspend */
|
||||
break;
|
||||
case 0x30: /* Erase resume */
|
||||
s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
|
||||
break;
|
||||
|
||||
case 0xf0: /* Reset NAND Flash core */
|
||||
onenand_reset(s, 0);
|
||||
break;
|
||||
case 0xf3: /* Reset OneNAND */
|
||||
onenand_reset(s, 0);
|
||||
break;
|
||||
|
||||
case 0x65: /* OTP Access */
|
||||
s->intstatus |= ONEN_INT;
|
||||
s->blk_cur = NULL;
|
||||
s->current = s->otp;
|
||||
s->secs_cur = 1 << (BLOCK_SHIFT - 9);
|
||||
s->addr[ONEN_BUF_BLOCK] = 0;
|
||||
s->otpmode = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
s->status |= ONEN_ERR_CMD;
|
||||
s->intstatus |= ONEN_INT;
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "unknown OneNAND command %x\n",
|
||||
s->command);
|
||||
}
|
||||
|
||||
onenand_intr_update(s);
|
||||
}
|
||||
|
||||
static uint64_t onenand_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
OneNANDState *s = (OneNANDState *) opaque;
|
||||
int offset = addr >> s->shift;
|
||||
|
||||
switch (offset) {
|
||||
case 0x0000 ... 0xbffe:
|
||||
return lduw_le_p(s->boot[0] + addr);
|
||||
|
||||
case 0xf000: /* Manufacturer ID */
|
||||
return s->id.man;
|
||||
case 0xf001: /* Device ID */
|
||||
return s->id.dev;
|
||||
case 0xf002: /* Version ID */
|
||||
return s->id.ver;
|
||||
/* TODO: get the following values from a real chip! */
|
||||
case 0xf003: /* Data Buffer size */
|
||||
return 1 << PAGE_SHIFT;
|
||||
case 0xf004: /* Boot Buffer size */
|
||||
return 0x200;
|
||||
case 0xf005: /* Amount of buffers */
|
||||
return 1 | (2 << 8);
|
||||
case 0xf006: /* Technology */
|
||||
return 0;
|
||||
|
||||
case 0xf100 ... 0xf107: /* Start addresses */
|
||||
return s->addr[offset - 0xf100];
|
||||
|
||||
case 0xf200: /* Start buffer */
|
||||
return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
|
||||
|
||||
case 0xf220: /* Command */
|
||||
return s->command;
|
||||
case 0xf221: /* System Configuration 1 */
|
||||
return s->config[0] & 0xffe0;
|
||||
case 0xf222: /* System Configuration 2 */
|
||||
return s->config[1];
|
||||
|
||||
case 0xf240: /* Controller Status */
|
||||
return s->status;
|
||||
case 0xf241: /* Interrupt */
|
||||
return s->intstatus;
|
||||
case 0xf24c: /* Unlock Start Block Address */
|
||||
return s->unladdr[0];
|
||||
case 0xf24d: /* Unlock End Block Address */
|
||||
return s->unladdr[1];
|
||||
case 0xf24e: /* Write Protection Status */
|
||||
return s->wpstatus;
|
||||
|
||||
case 0xff00: /* ECC Status */
|
||||
return 0x00;
|
||||
case 0xff01: /* ECC Result of main area data */
|
||||
case 0xff02: /* ECC Result of spare area data */
|
||||
case 0xff03: /* ECC Result of main area data */
|
||||
case 0xff04: /* ECC Result of spare area data */
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"onenand: ECC result registers unimplemented\n");
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "read of unknown OneNAND register 0x%x\n",
|
||||
offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void onenand_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
OneNANDState *s = (OneNANDState *) opaque;
|
||||
int offset = addr >> s->shift;
|
||||
int sec;
|
||||
|
||||
switch (offset) {
|
||||
case 0x0000 ... 0x01ff:
|
||||
case 0x8000 ... 0x800f:
|
||||
if (s->cycle) {
|
||||
s->cycle = 0;
|
||||
|
||||
if (value == 0x0000) {
|
||||
SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
|
||||
onenand_load_main(s, sec,
|
||||
1 << (PAGE_SHIFT - 9), s->data[0][0]);
|
||||
s->addr[ONEN_BUF_PAGE] += 4;
|
||||
s->addr[ONEN_BUF_PAGE] &= 0xff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case 0x00f0: /* Reset OneNAND */
|
||||
onenand_reset(s, 0);
|
||||
break;
|
||||
|
||||
case 0x00e0: /* Load Data into Buffer */
|
||||
s->cycle = 1;
|
||||
break;
|
||||
|
||||
case 0x0090: /* Read Identification Data */
|
||||
memset(s->boot[0], 0, 3 << s->shift);
|
||||
s->boot[0][0 << s->shift] = s->id.man & 0xff;
|
||||
s->boot[0][1 << s->shift] = s->id.dev & 0xff;
|
||||
s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"unknown OneNAND boot command %" PRIx64 "\n",
|
||||
value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xf100 ... 0xf107: /* Start addresses */
|
||||
s->addr[offset - 0xf100] = value;
|
||||
break;
|
||||
|
||||
case 0xf200: /* Start buffer */
|
||||
s->bufaddr = (value >> 8) & 0xf;
|
||||
if (PAGE_SHIFT == 11)
|
||||
s->count = (value & 3) ?: 4;
|
||||
else if (PAGE_SHIFT == 10)
|
||||
s->count = (value & 1) ?: 2;
|
||||
break;
|
||||
|
||||
case 0xf220: /* Command */
|
||||
if (s->intstatus & (1 << 15))
|
||||
break;
|
||||
s->command = value;
|
||||
onenand_command(s);
|
||||
break;
|
||||
case 0xf221: /* System Configuration 1 */
|
||||
s->config[0] = value;
|
||||
onenand_intr_update(s);
|
||||
qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
|
||||
break;
|
||||
case 0xf222: /* System Configuration 2 */
|
||||
s->config[1] = value;
|
||||
break;
|
||||
|
||||
case 0xf241: /* Interrupt */
|
||||
s->intstatus &= value;
|
||||
if ((1 << 15) & ~s->intstatus)
|
||||
s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
|
||||
ONEN_ERR_PROG | ONEN_ERR_LOAD);
|
||||
onenand_intr_update(s);
|
||||
break;
|
||||
case 0xf24c: /* Unlock Start Block Address */
|
||||
s->unladdr[0] = value & (s->blocks - 1);
|
||||
/* For some reason we have to set the end address to by default
|
||||
* be same as start because the software forgets to write anything
|
||||
* in there. */
|
||||
s->unladdr[1] = value & (s->blocks - 1);
|
||||
break;
|
||||
case 0xf24d: /* Unlock End Block Address */
|
||||
s->unladdr[1] = value & (s->blocks - 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"write to unknown OneNAND register 0x%x\n",
|
||||
offset);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps onenand_ops = {
|
||||
.read = onenand_read,
|
||||
.write = onenand_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void onenand_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
OneNANDState *s = ONE_NAND(dev);
|
||||
uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
|
||||
void *ram;
|
||||
Error *local_err = NULL;
|
||||
|
||||
s->base = (hwaddr)-1;
|
||||
s->rdy = NULL;
|
||||
s->blocks = size >> BLOCK_SHIFT;
|
||||
s->secs = size >> 9;
|
||||
s->blockwp = g_malloc(s->blocks);
|
||||
s->density_mask = (s->id.dev & 0x08)
|
||||
? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &onenand_ops, s, "onenand",
|
||||
0x10000 << s->shift);
|
||||
if (!s->blk) {
|
||||
s->image = memset(g_malloc(size + (size >> 5)),
|
||||
0xff, size + (size >> 5));
|
||||
} else {
|
||||
if (!blk_supports_write_perm(s->blk)) {
|
||||
error_setg(errp, "Can't use a read-only drive");
|
||||
return;
|
||||
}
|
||||
blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
|
||||
BLK_PERM_ALL, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
s->blk_cur = s->blk;
|
||||
}
|
||||
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
|
||||
0xff, (64 + 2) << PAGE_SHIFT);
|
||||
memory_region_init_ram_nomigrate(&s->ram, OBJECT(s), "onenand.ram",
|
||||
0xc000 << s->shift, &error_fatal);
|
||||
vmstate_register_ram_global(&s->ram);
|
||||
ram = memory_region_get_ram_ptr(&s->ram);
|
||||
s->boot[0] = ram + (0x0000 << s->shift);
|
||||
s->boot[1] = ram + (0x8000 << s->shift);
|
||||
s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
|
||||
s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
|
||||
s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
|
||||
s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
|
||||
onenand_mem_setup(s);
|
||||
sysbus_init_irq(sbd, &s->intr);
|
||||
sysbus_init_mmio(sbd, &s->container);
|
||||
vmstate_register(VMSTATE_IF(dev),
|
||||
((s->shift & 0x7f) << 24)
|
||||
| ((s->id.man & 0xff) << 16)
|
||||
| ((s->id.dev & 0xff) << 8)
|
||||
| (s->id.ver & 0xff),
|
||||
&vmstate_onenand, s);
|
||||
}
|
||||
|
||||
static Property onenand_properties[] = {
|
||||
DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
|
||||
DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
|
||||
DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
|
||||
DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
|
||||
DEFINE_PROP_DRIVE("drive", OneNANDState, blk),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void onenand_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = onenand_realize;
|
||||
device_class_set_legacy_reset(dc, onenand_system_reset);
|
||||
device_class_set_props(dc, onenand_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo onenand_info = {
|
||||
.name = TYPE_ONE_NAND,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(OneNANDState),
|
||||
.class_init = onenand_class_init,
|
||||
};
|
||||
|
||||
static void onenand_register_types(void)
|
||||
{
|
||||
type_register_static(&onenand_info);
|
||||
}
|
||||
|
||||
void *onenand_raw_otp(DeviceState *onenand_device)
|
||||
{
|
||||
OneNANDState *s = ONE_NAND(onenand_device);
|
||||
|
||||
return s->otp;
|
||||
}
|
||||
|
||||
type_init(onenand_register_types)
|
|
@ -28,7 +28,6 @@ struct omap_uart_s {
|
|||
MemoryRegion iomem;
|
||||
hwaddr base;
|
||||
SerialMM *serial; /* TODO */
|
||||
struct omap_target_agent_s *ta;
|
||||
omap_clk fclk;
|
||||
qemu_irq irq;
|
||||
|
||||
|
@ -36,8 +35,6 @@ struct omap_uart_s {
|
|||
uint8_t syscontrol;
|
||||
uint8_t wkup;
|
||||
uint8_t cfps;
|
||||
uint8_t mdr[2];
|
||||
uint8_t scr;
|
||||
uint8_t clksel;
|
||||
};
|
||||
|
||||
|
@ -66,113 +63,3 @@ struct omap_uart_s *omap_uart_init(hwaddr base,
|
|||
DEVICE_NATIVE_ENDIAN);
|
||||
return s;
|
||||
}
|
||||
|
||||
static uint64_t omap_uart_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
struct omap_uart_s *s = opaque;
|
||||
|
||||
if (size == 4) {
|
||||
return omap_badwidth_read8(opaque, addr);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x20: /* MDR1 */
|
||||
return s->mdr[0];
|
||||
case 0x24: /* MDR2 */
|
||||
return s->mdr[1];
|
||||
case 0x40: /* SCR */
|
||||
return s->scr;
|
||||
case 0x44: /* SSR */
|
||||
return 0x0;
|
||||
case 0x48: /* EBLR (OMAP2) */
|
||||
return s->eblr;
|
||||
case 0x4C: /* OSC_12M_SEL (OMAP1) */
|
||||
return s->clksel;
|
||||
case 0x50: /* MVR */
|
||||
return 0x30;
|
||||
case 0x54: /* SYSC (OMAP2) */
|
||||
return s->syscontrol;
|
||||
case 0x58: /* SYSS (OMAP2) */
|
||||
return 1;
|
||||
case 0x5c: /* WER (OMAP2) */
|
||||
return s->wkup;
|
||||
case 0x60: /* CFPS (OMAP2) */
|
||||
return s->cfps;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_uart_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
struct omap_uart_s *s = opaque;
|
||||
|
||||
if (size == 4) {
|
||||
omap_badwidth_write8(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x20: /* MDR1 */
|
||||
s->mdr[0] = value & 0x7f;
|
||||
break;
|
||||
case 0x24: /* MDR2 */
|
||||
s->mdr[1] = value & 0xff;
|
||||
break;
|
||||
case 0x40: /* SCR */
|
||||
s->scr = value & 0xff;
|
||||
break;
|
||||
case 0x48: /* EBLR (OMAP2) */
|
||||
s->eblr = value & 0xff;
|
||||
break;
|
||||
case 0x4C: /* OSC_12M_SEL (OMAP1) */
|
||||
s->clksel = value & 1;
|
||||
break;
|
||||
case 0x44: /* SSR */
|
||||
case 0x50: /* MVR */
|
||||
case 0x58: /* SYSS (OMAP2) */
|
||||
OMAP_RO_REG(addr);
|
||||
break;
|
||||
case 0x54: /* SYSC (OMAP2) */
|
||||
s->syscontrol = value & 0x1d;
|
||||
if (value & 2) {
|
||||
omap_uart_reset(s);
|
||||
}
|
||||
break;
|
||||
case 0x5c: /* WER (OMAP2) */
|
||||
s->wkup = value & 0x7f;
|
||||
break;
|
||||
case 0x60: /* CFPS (OMAP2) */
|
||||
s->cfps = value & 0xff;
|
||||
break;
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_uart_ops = {
|
||||
.read = omap_uart_read,
|
||||
.write = omap_uart_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
|
||||
struct omap_target_agent_s *ta,
|
||||
qemu_irq irq, omap_clk fclk, omap_clk iclk,
|
||||
qemu_irq txdma, qemu_irq rxdma,
|
||||
const char *label, Chardev *chr)
|
||||
{
|
||||
hwaddr base = omap_l4_attach(ta, 0, NULL);
|
||||
struct omap_uart_s *s = omap_uart_init(base, irq,
|
||||
fclk, iclk, txdma, rxdma, label, chr);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_uart_ops, s, "omap.uart", 0x100);
|
||||
|
||||
s->ta = ta;
|
||||
|
||||
memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -34,13 +34,19 @@ void qemu_set_irq(qemu_irq irq, int level)
|
|||
irq->handler(irq->opaque, irq->n, level);
|
||||
}
|
||||
|
||||
static void init_irq_fields(IRQState *irq, qemu_irq_handler handler,
|
||||
void *opaque, int n)
|
||||
{
|
||||
irq->handler = handler;
|
||||
irq->opaque = opaque;
|
||||
irq->n = n;
|
||||
}
|
||||
|
||||
void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque,
|
||||
int n)
|
||||
{
|
||||
object_initialize(irq, sizeof(*irq), TYPE_IRQ);
|
||||
irq->handler = handler;
|
||||
irq->opaque = opaque;
|
||||
irq->n = n;
|
||||
init_irq_fields(irq, handler, opaque, n);
|
||||
}
|
||||
|
||||
qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
|
||||
|
@ -66,11 +72,8 @@ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
|
|||
|
||||
qemu_irq qemu_allocate_irq(qemu_irq_handler handler, void *opaque, int n)
|
||||
{
|
||||
IRQState *irq;
|
||||
|
||||
irq = g_new(IRQState, 1);
|
||||
qemu_init_irq(irq, handler, opaque, n);
|
||||
|
||||
IRQState *irq = IRQ(object_new(TYPE_IRQ));
|
||||
init_irq_fields(irq, handler, opaque, n);
|
||||
return irq;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,9 +66,6 @@ config BOCHS_DISPLAY
|
|||
select VGA
|
||||
select EDID
|
||||
|
||||
config BLIZZARD
|
||||
bool
|
||||
|
||||
config FRAMEBUFFER
|
||||
bool
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,13 +22,9 @@ system_ss.add(when: 'CONFIG_VGA_MMIO', if_true: files('vga-mmio.c'))
|
|||
system_ss.add(when: 'CONFIG_VMWARE_VGA', if_true: files('vmware_vga.c'))
|
||||
system_ss.add(when: 'CONFIG_BOCHS_DISPLAY', if_true: files('bochs-display.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_BLIZZARD', if_true: files('blizzard.c'))
|
||||
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_fimd.c'))
|
||||
system_ss.add(when: 'CONFIG_FRAMEBUFFER', if_true: files('framebuffer.c'))
|
||||
system_ss.add(when: 'CONFIG_ZAURUS', if_true: files('tc6393xb.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dss.c'))
|
||||
system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_lcd.c'))
|
||||
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_fb.c'))
|
||||
system_ss.add(when: 'CONFIG_SM501', if_true: files('sm501.c'))
|
||||
system_ss.add(when: 'CONFIG_TCX', if_true: files('tcx.c'))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,568 +0,0 @@
|
|||
/*
|
||||
* Toshiba TC6393XB I/O Controller.
|
||||
* Found in Sharp Zaurus SL-6000 (tosa) or some
|
||||
* Toshiba e-Series PDAs.
|
||||
*
|
||||
* Most features are currently unsupported!!!
|
||||
*
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/display/tc6393xb.h"
|
||||
#include "exec/memory.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "ui/console.h"
|
||||
#include "ui/pixel_ops.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
#define IRQ_TC6393_NAND 0
|
||||
#define IRQ_TC6393_MMC 1
|
||||
#define IRQ_TC6393_OHCI 2
|
||||
#define IRQ_TC6393_SERIAL 3
|
||||
#define IRQ_TC6393_FB 4
|
||||
|
||||
#define TC6393XB_NR_IRQS 8
|
||||
|
||||
#define TC6393XB_GPIOS 16
|
||||
|
||||
#define SCR_REVID 0x08 /* b Revision ID */
|
||||
#define SCR_ISR 0x50 /* b Interrupt Status */
|
||||
#define SCR_IMR 0x52 /* b Interrupt Mask */
|
||||
#define SCR_IRR 0x54 /* b Interrupt Routing */
|
||||
#define SCR_GPER 0x60 /* w GP Enable */
|
||||
#define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */
|
||||
#define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */
|
||||
#define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */
|
||||
#define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */
|
||||
#define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */
|
||||
#define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */
|
||||
#define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */
|
||||
#define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */
|
||||
#define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */
|
||||
#define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */
|
||||
#define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */
|
||||
#define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */
|
||||
#define SCR_CCR 0x98 /* w Clock Control */
|
||||
#define SCR_PLL2CR 0x9a /* w PLL2 Control */
|
||||
#define SCR_PLL1CR 0x9c /* l PLL1 Control */
|
||||
#define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */
|
||||
#define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */
|
||||
#define SCR_FER 0xe0 /* b Function Enable */
|
||||
#define SCR_MCR 0xe4 /* w Mode Control */
|
||||
#define SCR_CONFIG 0xfc /* b Configuration Control */
|
||||
#define SCR_DEBUG 0xff /* b Debug */
|
||||
|
||||
#define NAND_CFG_COMMAND 0x04 /* w Command */
|
||||
#define NAND_CFG_BASE 0x10 /* l Control Base Address */
|
||||
#define NAND_CFG_INTP 0x3d /* b Interrupt Pin */
|
||||
#define NAND_CFG_INTE 0x48 /* b Int Enable */
|
||||
#define NAND_CFG_EC 0x4a /* b Event Control */
|
||||
#define NAND_CFG_ICC 0x4c /* b Internal Clock Control */
|
||||
#define NAND_CFG_ECCC 0x5b /* b ECC Control */
|
||||
#define NAND_CFG_NFTC 0x60 /* b NAND Flash Transaction Control */
|
||||
#define NAND_CFG_NFM 0x61 /* b NAND Flash Monitor */
|
||||
#define NAND_CFG_NFPSC 0x62 /* b NAND Flash Power Supply Control */
|
||||
#define NAND_CFG_NFDC 0x63 /* b NAND Flash Detect Control */
|
||||
|
||||
#define NAND_DATA 0x00 /* l Data */
|
||||
#define NAND_MODE 0x04 /* b Mode */
|
||||
#define NAND_STATUS 0x05 /* b Status */
|
||||
#define NAND_ISR 0x06 /* b Interrupt Status */
|
||||
#define NAND_IMR 0x07 /* b Interrupt Mask */
|
||||
|
||||
#define NAND_MODE_WP 0x80
|
||||
#define NAND_MODE_CE 0x10
|
||||
#define NAND_MODE_ALE 0x02
|
||||
#define NAND_MODE_CLE 0x01
|
||||
#define NAND_MODE_ECC_MASK 0x60
|
||||
#define NAND_MODE_ECC_EN 0x20
|
||||
#define NAND_MODE_ECC_READ 0x40
|
||||
#define NAND_MODE_ECC_RST 0x60
|
||||
|
||||
struct TC6393xbState {
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
qemu_irq *sub_irqs;
|
||||
struct {
|
||||
uint8_t ISR;
|
||||
uint8_t IMR;
|
||||
uint8_t IRR;
|
||||
uint16_t GPER;
|
||||
uint8_t GPI_SR[3];
|
||||
uint8_t GPI_IMR[3];
|
||||
uint8_t GPI_EDER[3];
|
||||
uint8_t GPI_LIR[3];
|
||||
uint8_t GP_IARCR[3];
|
||||
uint8_t GP_IARLCR[3];
|
||||
uint8_t GPI_BCR[3];
|
||||
uint16_t GPA_IARCR;
|
||||
uint16_t GPA_IARLCR;
|
||||
uint16_t CCR;
|
||||
uint16_t PLL2CR;
|
||||
uint32_t PLL1CR;
|
||||
uint8_t DIARCR;
|
||||
uint8_t DBOCR;
|
||||
uint8_t FER;
|
||||
uint16_t MCR;
|
||||
uint8_t CONFIG;
|
||||
uint8_t DEBUG;
|
||||
} scr;
|
||||
uint32_t gpio_dir;
|
||||
uint32_t gpio_level;
|
||||
uint32_t prev_level;
|
||||
qemu_irq handler[TC6393XB_GPIOS];
|
||||
qemu_irq *gpio_in;
|
||||
|
||||
struct {
|
||||
uint8_t mode;
|
||||
uint8_t isr;
|
||||
uint8_t imr;
|
||||
} nand;
|
||||
int nand_enable;
|
||||
uint32_t nand_phys;
|
||||
DeviceState *flash;
|
||||
ECCState ecc;
|
||||
|
||||
QemuConsole *con;
|
||||
MemoryRegion vram;
|
||||
uint16_t *vram_ptr;
|
||||
uint32_t scr_width, scr_height; /* in pixels */
|
||||
qemu_irq l3v;
|
||||
unsigned blank : 1,
|
||||
blanked : 1;
|
||||
};
|
||||
|
||||
static void tc6393xb_gpio_set(void *opaque, int line, int level)
|
||||
{
|
||||
// TC6393xbState *s = opaque;
|
||||
|
||||
if (line > TC6393XB_GPIOS) {
|
||||
printf("%s: No GPIO pin %i\n", __func__, line);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: how does the chip reflect the GPIO input level change?
|
||||
}
|
||||
|
||||
static void tc6393xb_gpio_handler_update(TC6393xbState *s)
|
||||
{
|
||||
uint32_t level, diff;
|
||||
int bit;
|
||||
|
||||
level = s->gpio_level & s->gpio_dir;
|
||||
level &= MAKE_64BIT_MASK(0, TC6393XB_GPIOS);
|
||||
|
||||
for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
|
||||
bit = ctz32(diff);
|
||||
qemu_set_irq(s->handler[bit], (level >> bit) & 1);
|
||||
}
|
||||
|
||||
s->prev_level = level;
|
||||
}
|
||||
|
||||
qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
|
||||
{
|
||||
return s->l3v;
|
||||
}
|
||||
|
||||
static void tc6393xb_l3v(void *opaque, int line, int level)
|
||||
{
|
||||
TC6393xbState *s = opaque;
|
||||
s->blank = !level;
|
||||
fprintf(stderr, "L3V: %d\n", level);
|
||||
}
|
||||
|
||||
static void tc6393xb_sub_irq(void *opaque, int line, int level) {
|
||||
TC6393xbState *s = opaque;
|
||||
uint8_t isr = s->scr.ISR;
|
||||
if (level)
|
||||
isr |= 1 << line;
|
||||
else
|
||||
isr &= ~(1 << line);
|
||||
s->scr.ISR = isr;
|
||||
qemu_set_irq(s->irq, isr & s->scr.IMR);
|
||||
}
|
||||
|
||||
#define SCR_REG_B(N) \
|
||||
case SCR_ ##N: return s->scr.N
|
||||
#define SCR_REG_W(N) \
|
||||
case SCR_ ##N: return s->scr.N; \
|
||||
case SCR_ ##N + 1: return s->scr.N >> 8;
|
||||
#define SCR_REG_L(N) \
|
||||
case SCR_ ##N: return s->scr.N; \
|
||||
case SCR_ ##N + 1: return s->scr.N >> 8; \
|
||||
case SCR_ ##N + 2: return s->scr.N >> 16; \
|
||||
case SCR_ ##N + 3: return s->scr.N >> 24;
|
||||
#define SCR_REG_A(N) \
|
||||
case SCR_ ##N(0): return s->scr.N[0]; \
|
||||
case SCR_ ##N(1): return s->scr.N[1]; \
|
||||
case SCR_ ##N(2): return s->scr.N[2]
|
||||
|
||||
static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr)
|
||||
{
|
||||
switch (addr) {
|
||||
case SCR_REVID:
|
||||
return 3;
|
||||
case SCR_REVID+1:
|
||||
return 0;
|
||||
SCR_REG_B(ISR);
|
||||
SCR_REG_B(IMR);
|
||||
SCR_REG_B(IRR);
|
||||
SCR_REG_W(GPER);
|
||||
SCR_REG_A(GPI_SR);
|
||||
SCR_REG_A(GPI_IMR);
|
||||
SCR_REG_A(GPI_EDER);
|
||||
SCR_REG_A(GPI_LIR);
|
||||
case SCR_GPO_DSR(0):
|
||||
case SCR_GPO_DSR(1):
|
||||
case SCR_GPO_DSR(2):
|
||||
return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
|
||||
case SCR_GPO_DOECR(0):
|
||||
case SCR_GPO_DOECR(1):
|
||||
case SCR_GPO_DOECR(2):
|
||||
return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
|
||||
SCR_REG_A(GP_IARCR);
|
||||
SCR_REG_A(GP_IARLCR);
|
||||
SCR_REG_A(GPI_BCR);
|
||||
SCR_REG_W(GPA_IARCR);
|
||||
SCR_REG_W(GPA_IARLCR);
|
||||
SCR_REG_W(CCR);
|
||||
SCR_REG_W(PLL2CR);
|
||||
SCR_REG_L(PLL1CR);
|
||||
SCR_REG_B(DIARCR);
|
||||
SCR_REG_B(DBOCR);
|
||||
SCR_REG_B(FER);
|
||||
SCR_REG_W(MCR);
|
||||
SCR_REG_B(CONFIG);
|
||||
SCR_REG_B(DEBUG);
|
||||
}
|
||||
fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
|
||||
return 0;
|
||||
}
|
||||
#undef SCR_REG_B
|
||||
#undef SCR_REG_W
|
||||
#undef SCR_REG_L
|
||||
#undef SCR_REG_A
|
||||
|
||||
#define SCR_REG_B(N) \
|
||||
case SCR_ ##N: s->scr.N = value; return;
|
||||
#define SCR_REG_W(N) \
|
||||
case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
|
||||
case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
|
||||
#define SCR_REG_L(N) \
|
||||
case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
|
||||
case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return; \
|
||||
case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return; \
|
||||
case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
|
||||
#define SCR_REG_A(N) \
|
||||
case SCR_ ##N(0): s->scr.N[0] = value; return; \
|
||||
case SCR_ ##N(1): s->scr.N[1] = value; return; \
|
||||
case SCR_ ##N(2): s->scr.N[2] = value; return
|
||||
|
||||
static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
|
||||
{
|
||||
switch (addr) {
|
||||
SCR_REG_B(ISR);
|
||||
SCR_REG_B(IMR);
|
||||
SCR_REG_B(IRR);
|
||||
SCR_REG_W(GPER);
|
||||
SCR_REG_A(GPI_SR);
|
||||
SCR_REG_A(GPI_IMR);
|
||||
SCR_REG_A(GPI_EDER);
|
||||
SCR_REG_A(GPI_LIR);
|
||||
case SCR_GPO_DSR(0):
|
||||
case SCR_GPO_DSR(1):
|
||||
case SCR_GPO_DSR(2):
|
||||
s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
|
||||
tc6393xb_gpio_handler_update(s);
|
||||
return;
|
||||
case SCR_GPO_DOECR(0):
|
||||
case SCR_GPO_DOECR(1):
|
||||
case SCR_GPO_DOECR(2):
|
||||
s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
|
||||
tc6393xb_gpio_handler_update(s);
|
||||
return;
|
||||
SCR_REG_A(GP_IARCR);
|
||||
SCR_REG_A(GP_IARLCR);
|
||||
SCR_REG_A(GPI_BCR);
|
||||
SCR_REG_W(GPA_IARCR);
|
||||
SCR_REG_W(GPA_IARLCR);
|
||||
SCR_REG_W(CCR);
|
||||
SCR_REG_W(PLL2CR);
|
||||
SCR_REG_L(PLL1CR);
|
||||
SCR_REG_B(DIARCR);
|
||||
SCR_REG_B(DBOCR);
|
||||
SCR_REG_B(FER);
|
||||
SCR_REG_W(MCR);
|
||||
SCR_REG_B(CONFIG);
|
||||
SCR_REG_B(DEBUG);
|
||||
}
|
||||
fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
|
||||
(uint32_t) addr, value & 0xff);
|
||||
}
|
||||
#undef SCR_REG_B
|
||||
#undef SCR_REG_W
|
||||
#undef SCR_REG_L
|
||||
#undef SCR_REG_A
|
||||
|
||||
static void tc6393xb_nand_irq(TC6393xbState *s) {
|
||||
qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
|
||||
(s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
|
||||
}
|
||||
|
||||
static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) {
|
||||
switch (addr) {
|
||||
case NAND_CFG_COMMAND:
|
||||
return s->nand_enable ? 2 : 0;
|
||||
case NAND_CFG_BASE:
|
||||
case NAND_CFG_BASE + 1:
|
||||
case NAND_CFG_BASE + 2:
|
||||
case NAND_CFG_BASE + 3:
|
||||
return s->nand_phys >> (addr - NAND_CFG_BASE);
|
||||
}
|
||||
fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
|
||||
return 0;
|
||||
}
|
||||
static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
|
||||
switch (addr) {
|
||||
case NAND_CFG_COMMAND:
|
||||
s->nand_enable = (value & 0x2);
|
||||
return;
|
||||
case NAND_CFG_BASE:
|
||||
case NAND_CFG_BASE + 1:
|
||||
case NAND_CFG_BASE + 2:
|
||||
case NAND_CFG_BASE + 3:
|
||||
s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
|
||||
s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
|
||||
(uint32_t) addr, value & 0xff);
|
||||
}
|
||||
|
||||
static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
|
||||
switch (addr) {
|
||||
case NAND_DATA + 0:
|
||||
case NAND_DATA + 1:
|
||||
case NAND_DATA + 2:
|
||||
case NAND_DATA + 3:
|
||||
return nand_getio(s->flash);
|
||||
case NAND_MODE:
|
||||
return s->nand.mode;
|
||||
case NAND_STATUS:
|
||||
return 0x14;
|
||||
case NAND_ISR:
|
||||
return s->nand.isr;
|
||||
case NAND_IMR:
|
||||
return s->nand.imr;
|
||||
}
|
||||
fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
|
||||
return 0;
|
||||
}
|
||||
static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
|
||||
// fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
|
||||
// (uint32_t) addr, value & 0xff);
|
||||
switch (addr) {
|
||||
case NAND_DATA + 0:
|
||||
case NAND_DATA + 1:
|
||||
case NAND_DATA + 2:
|
||||
case NAND_DATA + 3:
|
||||
nand_setio(s->flash, value);
|
||||
s->nand.isr |= 1;
|
||||
tc6393xb_nand_irq(s);
|
||||
return;
|
||||
case NAND_MODE:
|
||||
s->nand.mode = value;
|
||||
nand_setpins(s->flash,
|
||||
value & NAND_MODE_CLE,
|
||||
value & NAND_MODE_ALE,
|
||||
!(value & NAND_MODE_CE),
|
||||
value & NAND_MODE_WP,
|
||||
0); // FIXME: gnd
|
||||
switch (value & NAND_MODE_ECC_MASK) {
|
||||
case NAND_MODE_ECC_RST:
|
||||
ecc_reset(&s->ecc);
|
||||
break;
|
||||
case NAND_MODE_ECC_READ:
|
||||
// FIXME
|
||||
break;
|
||||
case NAND_MODE_ECC_EN:
|
||||
ecc_reset(&s->ecc);
|
||||
}
|
||||
return;
|
||||
case NAND_ISR:
|
||||
s->nand.isr = value;
|
||||
tc6393xb_nand_irq(s);
|
||||
return;
|
||||
case NAND_IMR:
|
||||
s->nand.imr = value;
|
||||
tc6393xb_nand_irq(s);
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
|
||||
(uint32_t) addr, value & 0xff);
|
||||
}
|
||||
|
||||
static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int i;
|
||||
uint16_t *data_buffer;
|
||||
uint8_t *data_display;
|
||||
|
||||
data_buffer = s->vram_ptr;
|
||||
data_display = surface_data(surface);
|
||||
for (i = 0; i < s->scr_height; i++) {
|
||||
int j;
|
||||
for (j = 0; j < s->scr_width; j++, data_display += 4, data_buffer++) {
|
||||
uint16_t color = *data_buffer;
|
||||
uint32_t dest_color = rgb_to_pixel32(
|
||||
((color & 0xf800) * 0x108) >> 11,
|
||||
((color & 0x7e0) * 0x41) >> 9,
|
||||
((color & 0x1f) * 0x21) >> 2
|
||||
);
|
||||
*(uint32_t *)data_display = dest_color;
|
||||
}
|
||||
}
|
||||
dpy_gfx_update_full(s->con);
|
||||
}
|
||||
|
||||
static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int i, w;
|
||||
uint8_t *d;
|
||||
|
||||
if (!full_update)
|
||||
return;
|
||||
|
||||
w = s->scr_width * surface_bytes_per_pixel(surface);
|
||||
d = surface_data(surface);
|
||||
for(i = 0; i < s->scr_height; i++) {
|
||||
memset(d, 0, w);
|
||||
d += surface_stride(surface);
|
||||
}
|
||||
|
||||
dpy_gfx_update_full(s->con);
|
||||
}
|
||||
|
||||
static void tc6393xb_update_display(void *opaque)
|
||||
{
|
||||
TC6393xbState *s = opaque;
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int full_update;
|
||||
|
||||
if (s->scr_width == 0 || s->scr_height == 0)
|
||||
return;
|
||||
|
||||
full_update = 0;
|
||||
if (s->blanked != s->blank) {
|
||||
s->blanked = s->blank;
|
||||
full_update = 1;
|
||||
}
|
||||
if (s->scr_width != surface_width(surface) ||
|
||||
s->scr_height != surface_height(surface)) {
|
||||
qemu_console_resize(s->con, s->scr_width, s->scr_height);
|
||||
full_update = 1;
|
||||
}
|
||||
if (s->blanked)
|
||||
tc6393xb_draw_blank(s, full_update);
|
||||
else
|
||||
tc6393xb_draw_graphic(s, full_update);
|
||||
}
|
||||
|
||||
|
||||
static uint64_t tc6393xb_readb(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
TC6393xbState *s = opaque;
|
||||
|
||||
switch (addr >> 8) {
|
||||
case 0:
|
||||
return tc6393xb_scr_readb(s, addr & 0xff);
|
||||
case 1:
|
||||
return tc6393xb_nand_cfg_readb(s, addr & 0xff);
|
||||
};
|
||||
|
||||
if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
|
||||
// return tc6393xb_nand_readb(s, addr & 0xff);
|
||||
uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
|
||||
// fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
|
||||
return d;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tc6393xb_writeb(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size) {
|
||||
TC6393xbState *s = opaque;
|
||||
|
||||
switch (addr >> 8) {
|
||||
case 0:
|
||||
tc6393xb_scr_writeb(s, addr & 0xff, value);
|
||||
return;
|
||||
case 1:
|
||||
tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
|
||||
return;
|
||||
};
|
||||
|
||||
if ((addr &~0xff) == s->nand_phys && s->nand_enable)
|
||||
tc6393xb_nand_writeb(s, addr & 0xff, value);
|
||||
else
|
||||
fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
|
||||
(uint32_t) addr, (int)value & 0xff);
|
||||
}
|
||||
|
||||
static const GraphicHwOps tc6393xb_gfx_ops = {
|
||||
.gfx_update = tc6393xb_update_display,
|
||||
};
|
||||
|
||||
TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
|
||||
{
|
||||
TC6393xbState *s;
|
||||
DriveInfo *nand;
|
||||
static const MemoryRegionOps tc6393xb_ops = {
|
||||
.read = tc6393xb_readb,
|
||||
.write = tc6393xb_writeb,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
};
|
||||
|
||||
s = g_new0(TC6393xbState, 1);
|
||||
s->irq = irq;
|
||||
s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
|
||||
|
||||
s->l3v = qemu_allocate_irq(tc6393xb_l3v, s, 0);
|
||||
s->blanked = 1;
|
||||
|
||||
s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
|
||||
|
||||
nand = drive_get(IF_MTD, 0, 0);
|
||||
s->flash = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
|
||||
NAND_MFR_TOSHIBA, 0x76);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &tc6393xb_ops, s, "tc6393xb", 0x10000);
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
|
||||
memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000,
|
||||
&error_fatal);
|
||||
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
|
||||
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
|
||||
s->scr_width = 480;
|
||||
s->scr_height = 640;
|
||||
s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
|
||||
|
||||
return s;
|
||||
}
|
|
@ -9,7 +9,6 @@ system_ss.add(when: 'CONFIG_STP2000', if_true: files('sparc32_dma.c'))
|
|||
system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dpdma.c'))
|
||||
system_ss.add(when: 'CONFIG_XLNX_ZDMA', if_true: files('xlnx-zdma.c'))
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
|
||||
system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c'))
|
||||
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
|
||||
system_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))
|
||||
system_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c'))
|
||||
|
|
|
@ -686,10 +686,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
|
|||
struct omap_dma_s *s = dma->opaque;
|
||||
|
||||
soc_dma_reset(s->dma);
|
||||
if (s->model < omap_dma_4)
|
||||
s->gcr = 0x0004;
|
||||
else
|
||||
s->gcr = 0x00010010;
|
||||
s->gcr = 0x0004;
|
||||
s->ocp = 0x00000000;
|
||||
memset(&s->irqstat, 0, sizeof(s->irqstat));
|
||||
memset(&s->irqen, 0, sizeof(s->irqen));
|
||||
|
@ -697,8 +694,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
|
|||
s->lcd_ch.condition = 0;
|
||||
s->lcd_ch.interrupts = 0;
|
||||
s->lcd_ch.dual = 0;
|
||||
if (s->model < omap_dma_4)
|
||||
omap_dma_enable_3_1_mapping(s);
|
||||
omap_dma_enable_3_1_mapping(s);
|
||||
for (i = 0; i < s->chans; i ++) {
|
||||
s->ch[i].suspend = 0;
|
||||
s->ch[i].prefetch = 0;
|
||||
|
@ -721,10 +717,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
|
|||
s->ch[i].repeat = 0;
|
||||
s->ch[i].auto_init = 0;
|
||||
s->ch[i].link_enabled = 0;
|
||||
if (s->model < omap_dma_4)
|
||||
s->ch[i].interrupts = 0x0003;
|
||||
else
|
||||
s->ch[i].interrupts = 0x0000;
|
||||
s->ch[i].interrupts = 0x0003;
|
||||
s->ch[i].status = 0;
|
||||
s->ch[i].cstatus = 0;
|
||||
s->ch[i].active = 0;
|
||||
|
@ -1587,7 +1580,6 @@ static void omap_dma_setcaps(struct omap_dma_s *s)
|
|||
case omap_dma_3_1:
|
||||
break;
|
||||
case omap_dma_3_2:
|
||||
case omap_dma_4:
|
||||
/* XXX Only available for sDMA */
|
||||
s->caps[0] =
|
||||
(1 << 19) | /* Constant Fill Capability */
|
||||
|
@ -1678,443 +1670,6 @@ struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
|
|||
return s->dma;
|
||||
}
|
||||
|
||||
static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
|
||||
{
|
||||
struct omap_dma_channel_s *ch = s->ch;
|
||||
uint32_t bmp, bit;
|
||||
|
||||
for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
|
||||
if (ch->status) {
|
||||
bmp |= bit;
|
||||
ch->cstatus |= ch->status;
|
||||
ch->status = 0;
|
||||
}
|
||||
if ((s->irqstat[0] |= s->irqen[0] & bmp))
|
||||
qemu_irq_raise(s->irq[0]);
|
||||
if ((s->irqstat[1] |= s->irqen[1] & bmp))
|
||||
qemu_irq_raise(s->irq[1]);
|
||||
if ((s->irqstat[2] |= s->irqen[2] & bmp))
|
||||
qemu_irq_raise(s->irq[2]);
|
||||
if ((s->irqstat[3] |= s->irqen[3] & bmp))
|
||||
qemu_irq_raise(s->irq[3]);
|
||||
}
|
||||
|
||||
static uint64_t omap_dma4_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
struct omap_dma_s *s = opaque;
|
||||
int irqn = 0, chnum;
|
||||
struct omap_dma_channel_s *ch;
|
||||
|
||||
if (size == 1) {
|
||||
return omap_badwidth_read16(opaque, addr);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* DMA4_REVISION */
|
||||
return 0x40;
|
||||
|
||||
case 0x14: /* DMA4_IRQSTATUS_L3 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x10: /* DMA4_IRQSTATUS_L2 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x0c: /* DMA4_IRQSTATUS_L1 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x08: /* DMA4_IRQSTATUS_L0 */
|
||||
return s->irqstat[irqn];
|
||||
|
||||
case 0x24: /* DMA4_IRQENABLE_L3 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x20: /* DMA4_IRQENABLE_L2 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x1c: /* DMA4_IRQENABLE_L1 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x18: /* DMA4_IRQENABLE_L0 */
|
||||
return s->irqen[irqn];
|
||||
|
||||
case 0x28: /* DMA4_SYSSTATUS */
|
||||
return 1; /* RESETDONE */
|
||||
|
||||
case 0x2c: /* DMA4_OCP_SYSCONFIG */
|
||||
return s->ocp;
|
||||
|
||||
case 0x64: /* DMA4_CAPS_0 */
|
||||
return s->caps[0];
|
||||
case 0x6c: /* DMA4_CAPS_2 */
|
||||
return s->caps[2];
|
||||
case 0x70: /* DMA4_CAPS_3 */
|
||||
return s->caps[3];
|
||||
case 0x74: /* DMA4_CAPS_4 */
|
||||
return s->caps[4];
|
||||
|
||||
case 0x78: /* DMA4_GCR */
|
||||
return s->gcr;
|
||||
|
||||
case 0x80 ... 0xfff:
|
||||
addr -= 0x80;
|
||||
chnum = addr / 0x60;
|
||||
ch = s->ch + chnum;
|
||||
addr -= chnum * 0x60;
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Per-channel registers */
|
||||
switch (addr) {
|
||||
case 0x00: /* DMA4_CCR */
|
||||
return (ch->buf_disable << 25) |
|
||||
(ch->src_sync << 24) |
|
||||
(ch->prefetch << 23) |
|
||||
((ch->sync & 0x60) << 14) |
|
||||
(ch->bs << 18) |
|
||||
(ch->transparent_copy << 17) |
|
||||
(ch->constant_fill << 16) |
|
||||
(ch->mode[1] << 14) |
|
||||
(ch->mode[0] << 12) |
|
||||
(0 << 10) | (0 << 9) |
|
||||
(ch->suspend << 8) |
|
||||
(ch->enable << 7) |
|
||||
(ch->priority << 6) |
|
||||
(ch->fs << 5) | (ch->sync & 0x1f);
|
||||
|
||||
case 0x04: /* DMA4_CLNK_CTRL */
|
||||
return (ch->link_enabled << 15) | ch->link_next_ch;
|
||||
|
||||
case 0x08: /* DMA4_CICR */
|
||||
return ch->interrupts;
|
||||
|
||||
case 0x0c: /* DMA4_CSR */
|
||||
return ch->cstatus;
|
||||
|
||||
case 0x10: /* DMA4_CSDP */
|
||||
return (ch->endian[0] << 21) |
|
||||
(ch->endian_lock[0] << 20) |
|
||||
(ch->endian[1] << 19) |
|
||||
(ch->endian_lock[1] << 18) |
|
||||
(ch->write_mode << 16) |
|
||||
(ch->burst[1] << 14) |
|
||||
(ch->pack[1] << 13) |
|
||||
(ch->translate[1] << 9) |
|
||||
(ch->burst[0] << 7) |
|
||||
(ch->pack[0] << 6) |
|
||||
(ch->translate[0] << 2) |
|
||||
(ch->data_type >> 1);
|
||||
|
||||
case 0x14: /* DMA4_CEN */
|
||||
return ch->elements;
|
||||
|
||||
case 0x18: /* DMA4_CFN */
|
||||
return ch->frames;
|
||||
|
||||
case 0x1c: /* DMA4_CSSA */
|
||||
return ch->addr[0];
|
||||
|
||||
case 0x20: /* DMA4_CDSA */
|
||||
return ch->addr[1];
|
||||
|
||||
case 0x24: /* DMA4_CSEI */
|
||||
return ch->element_index[0];
|
||||
|
||||
case 0x28: /* DMA4_CSFI */
|
||||
return ch->frame_index[0];
|
||||
|
||||
case 0x2c: /* DMA4_CDEI */
|
||||
return ch->element_index[1];
|
||||
|
||||
case 0x30: /* DMA4_CDFI */
|
||||
return ch->frame_index[1];
|
||||
|
||||
case 0x34: /* DMA4_CSAC */
|
||||
return ch->active_set.src & 0xffff;
|
||||
|
||||
case 0x38: /* DMA4_CDAC */
|
||||
return ch->active_set.dest & 0xffff;
|
||||
|
||||
case 0x3c: /* DMA4_CCEN */
|
||||
return ch->active_set.element;
|
||||
|
||||
case 0x40: /* DMA4_CCFN */
|
||||
return ch->active_set.frame;
|
||||
|
||||
case 0x44: /* DMA4_COLOR */
|
||||
/* XXX only in sDMA */
|
||||
return ch->color;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_dma4_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
struct omap_dma_s *s = opaque;
|
||||
int chnum, irqn = 0;
|
||||
struct omap_dma_channel_s *ch;
|
||||
|
||||
if (size == 1) {
|
||||
omap_badwidth_write16(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x14: /* DMA4_IRQSTATUS_L3 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x10: /* DMA4_IRQSTATUS_L2 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x0c: /* DMA4_IRQSTATUS_L1 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x08: /* DMA4_IRQSTATUS_L0 */
|
||||
s->irqstat[irqn] &= ~value;
|
||||
if (!s->irqstat[irqn])
|
||||
qemu_irq_lower(s->irq[irqn]);
|
||||
return;
|
||||
|
||||
case 0x24: /* DMA4_IRQENABLE_L3 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x20: /* DMA4_IRQENABLE_L2 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x1c: /* DMA4_IRQENABLE_L1 */
|
||||
irqn ++;
|
||||
/* fall through */
|
||||
case 0x18: /* DMA4_IRQENABLE_L0 */
|
||||
s->irqen[irqn] = value;
|
||||
return;
|
||||
|
||||
case 0x2c: /* DMA4_OCP_SYSCONFIG */
|
||||
if (value & 2) /* SOFTRESET */
|
||||
omap_dma_reset(s->dma);
|
||||
s->ocp = value & 0x3321;
|
||||
if (((s->ocp >> 12) & 3) == 3) { /* MIDLEMODE */
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid DMA power mode\n",
|
||||
__func__);
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x78: /* DMA4_GCR */
|
||||
s->gcr = value & 0x00ff00ff;
|
||||
if ((value & 0xff) == 0x00) { /* MAX_CHANNEL_FIFO_DEPTH */
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: wrong FIFO depth in GCR\n",
|
||||
__func__);
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x80 ... 0xfff:
|
||||
addr -= 0x80;
|
||||
chnum = addr / 0x60;
|
||||
ch = s->ch + chnum;
|
||||
addr -= chnum * 0x60;
|
||||
break;
|
||||
|
||||
case 0x00: /* DMA4_REVISION */
|
||||
case 0x28: /* DMA4_SYSSTATUS */
|
||||
case 0x64: /* DMA4_CAPS_0 */
|
||||
case 0x6c: /* DMA4_CAPS_2 */
|
||||
case 0x70: /* DMA4_CAPS_3 */
|
||||
case 0x74: /* DMA4_CAPS_4 */
|
||||
OMAP_RO_REG(addr);
|
||||
return;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Per-channel registers */
|
||||
switch (addr) {
|
||||
case 0x00: /* DMA4_CCR */
|
||||
ch->buf_disable = (value >> 25) & 1;
|
||||
ch->src_sync = (value >> 24) & 1; /* XXX For CamDMA must be 1 */
|
||||
if (ch->buf_disable && !ch->src_sync) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Buffering disable is not allowed in "
|
||||
"destination synchronised mode\n", __func__);
|
||||
}
|
||||
ch->prefetch = (value >> 23) & 1;
|
||||
ch->bs = (value >> 18) & 1;
|
||||
ch->transparent_copy = (value >> 17) & 1;
|
||||
ch->constant_fill = (value >> 16) & 1;
|
||||
ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
|
||||
ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
|
||||
ch->suspend = (value & 0x0100) >> 8;
|
||||
ch->priority = (value & 0x0040) >> 6;
|
||||
ch->fs = (value & 0x0020) >> 5;
|
||||
if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1]) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: For a packet transfer at least one port "
|
||||
"must be constant-addressed\n", __func__);
|
||||
}
|
||||
ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060);
|
||||
/* XXX must be 0x01 for CamDMA */
|
||||
|
||||
if (value & 0x0080)
|
||||
omap_dma_enable_channel(s, ch);
|
||||
else
|
||||
omap_dma_disable_channel(s, ch);
|
||||
|
||||
break;
|
||||
|
||||
case 0x04: /* DMA4_CLNK_CTRL */
|
||||
ch->link_enabled = (value >> 15) & 0x1;
|
||||
ch->link_next_ch = value & 0x1f;
|
||||
break;
|
||||
|
||||
case 0x08: /* DMA4_CICR */
|
||||
ch->interrupts = value & 0x09be;
|
||||
break;
|
||||
|
||||
case 0x0c: /* DMA4_CSR */
|
||||
ch->cstatus &= ~value;
|
||||
break;
|
||||
|
||||
case 0x10: /* DMA4_CSDP */
|
||||
ch->endian[0] =(value >> 21) & 1;
|
||||
ch->endian_lock[0] =(value >> 20) & 1;
|
||||
ch->endian[1] =(value >> 19) & 1;
|
||||
ch->endian_lock[1] =(value >> 18) & 1;
|
||||
if (ch->endian[0] != ch->endian[1]) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: DMA endianness conversion enable attempt\n",
|
||||
__func__);
|
||||
}
|
||||
ch->write_mode = (value >> 16) & 3;
|
||||
ch->burst[1] = (value & 0xc000) >> 14;
|
||||
ch->pack[1] = (value & 0x2000) >> 13;
|
||||
ch->translate[1] = (value & 0x1e00) >> 9;
|
||||
ch->burst[0] = (value & 0x0180) >> 7;
|
||||
ch->pack[0] = (value & 0x0040) >> 6;
|
||||
ch->translate[0] = (value & 0x003c) >> 2;
|
||||
if (ch->translate[0] | ch->translate[1]) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: bad MReqAddressTranslate sideband signal\n",
|
||||
__func__);
|
||||
}
|
||||
ch->data_type = 1 << (value & 3);
|
||||
if ((value & 3) == 3) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: bad data_type for DMA channel\n", __func__);
|
||||
ch->data_type >>= 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x14: /* DMA4_CEN */
|
||||
ch->set_update = 1;
|
||||
ch->elements = value & 0xffffff;
|
||||
break;
|
||||
|
||||
case 0x18: /* DMA4_CFN */
|
||||
ch->frames = value & 0xffff;
|
||||
ch->set_update = 1;
|
||||
break;
|
||||
|
||||
case 0x1c: /* DMA4_CSSA */
|
||||
ch->addr[0] = (hwaddr) (uint32_t) value;
|
||||
ch->set_update = 1;
|
||||
break;
|
||||
|
||||
case 0x20: /* DMA4_CDSA */
|
||||
ch->addr[1] = (hwaddr) (uint32_t) value;
|
||||
ch->set_update = 1;
|
||||
break;
|
||||
|
||||
case 0x24: /* DMA4_CSEI */
|
||||
ch->element_index[0] = (int16_t) value;
|
||||
ch->set_update = 1;
|
||||
break;
|
||||
|
||||
case 0x28: /* DMA4_CSFI */
|
||||
ch->frame_index[0] = (int32_t) value;
|
||||
ch->set_update = 1;
|
||||
break;
|
||||
|
||||
case 0x2c: /* DMA4_CDEI */
|
||||
ch->element_index[1] = (int16_t) value;
|
||||
ch->set_update = 1;
|
||||
break;
|
||||
|
||||
case 0x30: /* DMA4_CDFI */
|
||||
ch->frame_index[1] = (int32_t) value;
|
||||
ch->set_update = 1;
|
||||
break;
|
||||
|
||||
case 0x44: /* DMA4_COLOR */
|
||||
/* XXX only in sDMA */
|
||||
ch->color = value;
|
||||
break;
|
||||
|
||||
case 0x34: /* DMA4_CSAC */
|
||||
case 0x38: /* DMA4_CDAC */
|
||||
case 0x3c: /* DMA4_CCEN */
|
||||
case 0x40: /* DMA4_CCFN */
|
||||
OMAP_RO_REG(addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_dma4_ops = {
|
||||
.read = omap_dma4_read,
|
||||
.write = omap_dma4_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
|
||||
MemoryRegion *sysmem,
|
||||
struct omap_mpu_state_s *mpu, int fifo,
|
||||
int chans, omap_clk iclk, omap_clk fclk)
|
||||
{
|
||||
int i;
|
||||
struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
|
||||
|
||||
s->model = omap_dma_4;
|
||||
s->chans = chans;
|
||||
s->mpu = mpu;
|
||||
s->clk = fclk;
|
||||
|
||||
s->dma = soc_dma_init(s->chans);
|
||||
s->dma->freq = omap_clk_getrate(fclk);
|
||||
s->dma->transfer_fn = omap_dma_transfer_generic;
|
||||
s->dma->setup_fn = omap_dma_transfer_setup;
|
||||
s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
|
||||
s->dma->opaque = s;
|
||||
for (i = 0; i < s->chans; i ++) {
|
||||
s->ch[i].dma = &s->dma->ch[i];
|
||||
s->dma->ch[i].opaque = &s->ch[i];
|
||||
}
|
||||
|
||||
memcpy(&s->irq, irqs, sizeof(s->irq));
|
||||
s->intr_update = omap_dma_interrupts_4_update;
|
||||
|
||||
omap_dma_setcaps(s);
|
||||
omap_clk_adduser(s->clk, qemu_allocate_irq(omap_dma_clk_update, s, 0));
|
||||
omap_dma_reset(s->dma);
|
||||
omap_dma_clk_update(s, 0, !!s->dma->freq);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_dma4_ops, s, "omap.dma4", 0x1000);
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
|
||||
mpu->drq = s->dma->drq;
|
||||
|
||||
return s->dma;
|
||||
}
|
||||
|
||||
struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct soc_dma_s *dma)
|
||||
{
|
||||
struct omap_dma_s *s = dma->opaque;
|
||||
|
|
|
@ -1,591 +0,0 @@
|
|||
/*
|
||||
* Intel XScale PXA255/270 DMA controller.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Copyright (c) 2006 Thorsten Zitterell
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GPL.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define PXA255_DMA_NUM_CHANNELS 16
|
||||
#define PXA27X_DMA_NUM_CHANNELS 32
|
||||
|
||||
#define PXA2XX_DMA_NUM_REQUESTS 75
|
||||
|
||||
typedef struct {
|
||||
uint32_t descr;
|
||||
uint32_t src;
|
||||
uint32_t dest;
|
||||
uint32_t cmd;
|
||||
uint32_t state;
|
||||
int request;
|
||||
} PXA2xxDMAChannel;
|
||||
|
||||
#define TYPE_PXA2XX_DMA "pxa2xx-dma"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxDMAState, PXA2XX_DMA)
|
||||
|
||||
struct PXA2xxDMAState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t stopintr;
|
||||
uint32_t eorintr;
|
||||
uint32_t rasintr;
|
||||
uint32_t startintr;
|
||||
uint32_t endintr;
|
||||
|
||||
uint32_t align;
|
||||
uint32_t pio;
|
||||
|
||||
int channels;
|
||||
PXA2xxDMAChannel *chan;
|
||||
|
||||
uint8_t req[PXA2XX_DMA_NUM_REQUESTS];
|
||||
|
||||
/* Flag to avoid recursive DMA invocations. */
|
||||
int running;
|
||||
};
|
||||
|
||||
#define DCSR0 0x0000 /* DMA Control / Status register for Channel 0 */
|
||||
#define DCSR31 0x007c /* DMA Control / Status register for Channel 31 */
|
||||
#define DALGN 0x00a0 /* DMA Alignment register */
|
||||
#define DPCSR 0x00a4 /* DMA Programmed I/O Control Status register */
|
||||
#define DRQSR0 0x00e0 /* DMA DREQ<0> Status register */
|
||||
#define DRQSR1 0x00e4 /* DMA DREQ<1> Status register */
|
||||
#define DRQSR2 0x00e8 /* DMA DREQ<2> Status register */
|
||||
#define DINT 0x00f0 /* DMA Interrupt register */
|
||||
#define DRCMR0 0x0100 /* Request to Channel Map register 0 */
|
||||
#define DRCMR63 0x01fc /* Request to Channel Map register 63 */
|
||||
#define D_CH0 0x0200 /* Channel 0 Descriptor start */
|
||||
#define DRCMR64 0x1100 /* Request to Channel Map register 64 */
|
||||
#define DRCMR74 0x1128 /* Request to Channel Map register 74 */
|
||||
|
||||
/* Per-channel register */
|
||||
#define DDADR 0x00
|
||||
#define DSADR 0x01
|
||||
#define DTADR 0x02
|
||||
#define DCMD 0x03
|
||||
|
||||
/* Bit-field masks */
|
||||
#define DRCMR_CHLNUM 0x1f
|
||||
#define DRCMR_MAPVLD (1 << 7)
|
||||
#define DDADR_STOP (1 << 0)
|
||||
#define DDADR_BREN (1 << 1)
|
||||
#define DCMD_LEN 0x1fff
|
||||
#define DCMD_WIDTH(x) (1 << ((((x) >> 14) & 3) - 1))
|
||||
#define DCMD_SIZE(x) (4 << (((x) >> 16) & 3))
|
||||
#define DCMD_FLYBYT (1 << 19)
|
||||
#define DCMD_FLYBYS (1 << 20)
|
||||
#define DCMD_ENDIRQEN (1 << 21)
|
||||
#define DCMD_STARTIRQEN (1 << 22)
|
||||
#define DCMD_CMPEN (1 << 25)
|
||||
#define DCMD_FLOWTRG (1 << 28)
|
||||
#define DCMD_FLOWSRC (1 << 29)
|
||||
#define DCMD_INCTRGADDR (1 << 30)
|
||||
#define DCMD_INCSRCADDR (1 << 31)
|
||||
#define DCSR_BUSERRINTR (1 << 0)
|
||||
#define DCSR_STARTINTR (1 << 1)
|
||||
#define DCSR_ENDINTR (1 << 2)
|
||||
#define DCSR_STOPINTR (1 << 3)
|
||||
#define DCSR_RASINTR (1 << 4)
|
||||
#define DCSR_REQPEND (1 << 8)
|
||||
#define DCSR_EORINT (1 << 9)
|
||||
#define DCSR_CMPST (1 << 10)
|
||||
#define DCSR_MASKRUN (1 << 22)
|
||||
#define DCSR_RASIRQEN (1 << 23)
|
||||
#define DCSR_CLRCMPST (1 << 24)
|
||||
#define DCSR_SETCMPST (1 << 25)
|
||||
#define DCSR_EORSTOPEN (1 << 26)
|
||||
#define DCSR_EORJMPEN (1 << 27)
|
||||
#define DCSR_EORIRQEN (1 << 28)
|
||||
#define DCSR_STOPIRQEN (1 << 29)
|
||||
#define DCSR_NODESCFETCH (1 << 30)
|
||||
#define DCSR_RUN (1 << 31)
|
||||
|
||||
static inline void pxa2xx_dma_update(PXA2xxDMAState *s, int ch)
|
||||
{
|
||||
if (ch >= 0) {
|
||||
if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
|
||||
(s->chan[ch].state & DCSR_STOPINTR))
|
||||
s->stopintr |= 1 << ch;
|
||||
else
|
||||
s->stopintr &= ~(1 << ch);
|
||||
|
||||
if ((s->chan[ch].state & DCSR_EORIRQEN) &&
|
||||
(s->chan[ch].state & DCSR_EORINT))
|
||||
s->eorintr |= 1 << ch;
|
||||
else
|
||||
s->eorintr &= ~(1 << ch);
|
||||
|
||||
if ((s->chan[ch].state & DCSR_RASIRQEN) &&
|
||||
(s->chan[ch].state & DCSR_RASINTR))
|
||||
s->rasintr |= 1 << ch;
|
||||
else
|
||||
s->rasintr &= ~(1 << ch);
|
||||
|
||||
if (s->chan[ch].state & DCSR_STARTINTR)
|
||||
s->startintr |= 1 << ch;
|
||||
else
|
||||
s->startintr &= ~(1 << ch);
|
||||
|
||||
if (s->chan[ch].state & DCSR_ENDINTR)
|
||||
s->endintr |= 1 << ch;
|
||||
else
|
||||
s->endintr &= ~(1 << ch);
|
||||
}
|
||||
|
||||
if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
|
||||
qemu_irq_raise(s->irq);
|
||||
else
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
|
||||
static inline void pxa2xx_dma_descriptor_fetch(
|
||||
PXA2xxDMAState *s, int ch)
|
||||
{
|
||||
uint32_t desc[4];
|
||||
hwaddr daddr = s->chan[ch].descr & ~0xf;
|
||||
if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
|
||||
daddr += 32;
|
||||
|
||||
cpu_physical_memory_read(daddr, desc, 16);
|
||||
s->chan[ch].descr = desc[DDADR];
|
||||
s->chan[ch].src = desc[DSADR];
|
||||
s->chan[ch].dest = desc[DTADR];
|
||||
s->chan[ch].cmd = desc[DCMD];
|
||||
|
||||
if (s->chan[ch].cmd & DCMD_FLOWSRC)
|
||||
s->chan[ch].src &= ~3;
|
||||
if (s->chan[ch].cmd & DCMD_FLOWTRG)
|
||||
s->chan[ch].dest &= ~3;
|
||||
|
||||
if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
|
||||
printf("%s: unsupported mode in channel %i\n", __func__, ch);
|
||||
|
||||
if (s->chan[ch].cmd & DCMD_STARTIRQEN)
|
||||
s->chan[ch].state |= DCSR_STARTINTR;
|
||||
}
|
||||
|
||||
static void pxa2xx_dma_run(PXA2xxDMAState *s)
|
||||
{
|
||||
int c, srcinc, destinc;
|
||||
uint32_t n, size;
|
||||
uint32_t width;
|
||||
uint32_t length;
|
||||
uint8_t buffer[32];
|
||||
PXA2xxDMAChannel *ch;
|
||||
|
||||
if (s->running ++)
|
||||
return;
|
||||
|
||||
while (s->running) {
|
||||
s->running = 1;
|
||||
for (c = 0; c < s->channels; c ++) {
|
||||
ch = &s->chan[c];
|
||||
|
||||
while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
|
||||
/* Test for pending requests */
|
||||
if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
|
||||
break;
|
||||
|
||||
length = ch->cmd & DCMD_LEN;
|
||||
size = DCMD_SIZE(ch->cmd);
|
||||
width = DCMD_WIDTH(ch->cmd);
|
||||
|
||||
srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
|
||||
destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
|
||||
|
||||
while (length) {
|
||||
size = MIN(length, size);
|
||||
|
||||
for (n = 0; n < size; n += width) {
|
||||
cpu_physical_memory_read(ch->src, buffer + n, width);
|
||||
ch->src += srcinc;
|
||||
}
|
||||
|
||||
for (n = 0; n < size; n += width) {
|
||||
cpu_physical_memory_write(ch->dest, buffer + n, width);
|
||||
ch->dest += destinc;
|
||||
}
|
||||
|
||||
length -= size;
|
||||
|
||||
if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
|
||||
!ch->request) {
|
||||
ch->state |= DCSR_EORINT;
|
||||
if (ch->state & DCSR_EORSTOPEN)
|
||||
ch->state |= DCSR_STOPINTR;
|
||||
if ((ch->state & DCSR_EORJMPEN) &&
|
||||
!(ch->state & DCSR_NODESCFETCH))
|
||||
pxa2xx_dma_descriptor_fetch(s, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
|
||||
|
||||
/* Is the transfer complete now? */
|
||||
if (!length) {
|
||||
if (ch->cmd & DCMD_ENDIRQEN)
|
||||
ch->state |= DCSR_ENDINTR;
|
||||
|
||||
if ((ch->state & DCSR_NODESCFETCH) ||
|
||||
(ch->descr & DDADR_STOP) ||
|
||||
(ch->state & DCSR_EORSTOPEN)) {
|
||||
ch->state |= DCSR_STOPINTR;
|
||||
ch->state &= ~DCSR_RUN;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ch->state |= DCSR_STOPINTR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s->running --;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
|
||||
unsigned int channel;
|
||||
|
||||
if (size != 4) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n",
|
||||
__func__, size);
|
||||
return 5;
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case DRCMR64 ... DRCMR74:
|
||||
offset -= DRCMR64 - DRCMR0 - (64 << 2);
|
||||
/* Fall through */
|
||||
case DRCMR0 ... DRCMR63:
|
||||
channel = (offset - DRCMR0) >> 2;
|
||||
return s->req[channel];
|
||||
|
||||
case DRQSR0:
|
||||
case DRQSR1:
|
||||
case DRQSR2:
|
||||
return 0;
|
||||
|
||||
case DCSR0 ... DCSR31:
|
||||
channel = offset >> 2;
|
||||
if (s->chan[channel].request)
|
||||
return s->chan[channel].state | DCSR_REQPEND;
|
||||
return s->chan[channel].state;
|
||||
|
||||
case DINT:
|
||||
return s->stopintr | s->eorintr | s->rasintr |
|
||||
s->startintr | s->endintr;
|
||||
|
||||
case DALGN:
|
||||
return s->align;
|
||||
|
||||
case DPCSR:
|
||||
return s->pio;
|
||||
}
|
||||
|
||||
if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
|
||||
channel = (offset - D_CH0) >> 4;
|
||||
switch ((offset & 0x0f) >> 2) {
|
||||
case DDADR:
|
||||
return s->chan[channel].descr;
|
||||
case DSADR:
|
||||
return s->chan[channel].src;
|
||||
case DTADR:
|
||||
return s->chan[channel].dest;
|
||||
case DCMD:
|
||||
return s->chan[channel].cmd;
|
||||
}
|
||||
}
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
return 7;
|
||||
}
|
||||
|
||||
static void pxa2xx_dma_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
|
||||
unsigned int channel;
|
||||
|
||||
if (size != 4) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n",
|
||||
__func__, size);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case DRCMR64 ... DRCMR74:
|
||||
offset -= DRCMR64 - DRCMR0 - (64 << 2);
|
||||
/* Fall through */
|
||||
case DRCMR0 ... DRCMR63:
|
||||
channel = (offset - DRCMR0) >> 2;
|
||||
|
||||
if (value & DRCMR_MAPVLD)
|
||||
if ((value & DRCMR_CHLNUM) > s->channels)
|
||||
hw_error("%s: Bad DMA channel %i\n",
|
||||
__func__, (unsigned)value & DRCMR_CHLNUM);
|
||||
|
||||
s->req[channel] = value;
|
||||
break;
|
||||
|
||||
case DRQSR0:
|
||||
case DRQSR1:
|
||||
case DRQSR2:
|
||||
/* Nothing to do */
|
||||
break;
|
||||
|
||||
case DCSR0 ... DCSR31:
|
||||
channel = offset >> 2;
|
||||
s->chan[channel].state &= 0x0000071f & ~(value &
|
||||
(DCSR_EORINT | DCSR_ENDINTR |
|
||||
DCSR_STARTINTR | DCSR_BUSERRINTR));
|
||||
s->chan[channel].state |= value & 0xfc800000;
|
||||
|
||||
if (s->chan[channel].state & DCSR_STOPIRQEN)
|
||||
s->chan[channel].state &= ~DCSR_STOPINTR;
|
||||
|
||||
if (value & DCSR_NODESCFETCH) {
|
||||
/* No-descriptor-fetch mode */
|
||||
if (value & DCSR_RUN) {
|
||||
s->chan[channel].state &= ~DCSR_STOPINTR;
|
||||
pxa2xx_dma_run(s);
|
||||
}
|
||||
} else {
|
||||
/* Descriptor-fetch mode */
|
||||
if (value & DCSR_RUN) {
|
||||
s->chan[channel].state &= ~DCSR_STOPINTR;
|
||||
pxa2xx_dma_descriptor_fetch(s, channel);
|
||||
pxa2xx_dma_run(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Shouldn't matter as our DMA is synchronous. */
|
||||
if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
|
||||
s->chan[channel].state |= DCSR_STOPINTR;
|
||||
|
||||
if (value & DCSR_CLRCMPST)
|
||||
s->chan[channel].state &= ~DCSR_CMPST;
|
||||
if (value & DCSR_SETCMPST)
|
||||
s->chan[channel].state |= DCSR_CMPST;
|
||||
|
||||
pxa2xx_dma_update(s, channel);
|
||||
break;
|
||||
|
||||
case DALGN:
|
||||
s->align = value;
|
||||
break;
|
||||
|
||||
case DPCSR:
|
||||
s->pio = value & 0x80000001;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
|
||||
channel = (offset - D_CH0) >> 4;
|
||||
switch ((offset & 0x0f) >> 2) {
|
||||
case DDADR:
|
||||
s->chan[channel].descr = value;
|
||||
break;
|
||||
case DSADR:
|
||||
s->chan[channel].src = value;
|
||||
break;
|
||||
case DTADR:
|
||||
s->chan[channel].dest = value;
|
||||
break;
|
||||
case DCMD:
|
||||
s->chan[channel].cmd = value;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pxa2xx_dma_ops = {
|
||||
.read = pxa2xx_dma_read,
|
||||
.write = pxa2xx_dma_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void pxa2xx_dma_request(void *opaque, int req_num, int on)
|
||||
{
|
||||
PXA2xxDMAState *s = opaque;
|
||||
int ch;
|
||||
if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
|
||||
hw_error("%s: Bad DMA request %i\n", __func__, req_num);
|
||||
|
||||
if (!(s->req[req_num] & DRCMR_MAPVLD))
|
||||
return;
|
||||
ch = s->req[req_num] & DRCMR_CHLNUM;
|
||||
|
||||
if (!s->chan[ch].request && on)
|
||||
s->chan[ch].state |= DCSR_RASINTR;
|
||||
else
|
||||
s->chan[ch].state &= ~DCSR_RASINTR;
|
||||
if (s->chan[ch].request && !on)
|
||||
s->chan[ch].state |= DCSR_EORINT;
|
||||
|
||||
s->chan[ch].request = on;
|
||||
if (on) {
|
||||
pxa2xx_dma_run(s);
|
||||
pxa2xx_dma_update(s, ch);
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_dma_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
PXA2xxDMAState *s = PXA2XX_DMA(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
|
||||
|
||||
qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_dma_ops, s,
|
||||
"pxa2xx.dma", 0x00010000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
}
|
||||
|
||||
static void pxa2xx_dma_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PXA2xxDMAState *s = PXA2XX_DMA(dev);
|
||||
int i;
|
||||
|
||||
if (s->channels <= 0) {
|
||||
error_setg(errp, "channels value invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
s->chan = g_new0(PXA2xxDMAChannel, s->channels);
|
||||
|
||||
for (i = 0; i < s->channels; i ++)
|
||||
s->chan[i].state = DCSR_STOPINTR;
|
||||
}
|
||||
|
||||
DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("pxa2xx-dma");
|
||||
qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_new("pxa2xx-dma");
|
||||
qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static bool is_version_0(void *opaque, int version_id)
|
||||
{
|
||||
return version_id == 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pxa2xx_dma_chan = {
|
||||
.name = "pxa2xx_dma_chan",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(descr, PXA2xxDMAChannel),
|
||||
VMSTATE_UINT32(src, PXA2xxDMAChannel),
|
||||
VMSTATE_UINT32(dest, PXA2xxDMAChannel),
|
||||
VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
|
||||
VMSTATE_UINT32(state, PXA2xxDMAChannel),
|
||||
VMSTATE_INT32(request, PXA2xxDMAChannel),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_pxa2xx_dma = {
|
||||
.name = "pxa2xx_dma",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UNUSED_TEST(is_version_0, 4),
|
||||
VMSTATE_UINT32(stopintr, PXA2xxDMAState),
|
||||
VMSTATE_UINT32(eorintr, PXA2xxDMAState),
|
||||
VMSTATE_UINT32(rasintr, PXA2xxDMAState),
|
||||
VMSTATE_UINT32(startintr, PXA2xxDMAState),
|
||||
VMSTATE_UINT32(endintr, PXA2xxDMAState),
|
||||
VMSTATE_UINT32(align, PXA2xxDMAState),
|
||||
VMSTATE_UINT32(pio, PXA2xxDMAState),
|
||||
VMSTATE_BUFFER(req, PXA2xxDMAState),
|
||||
VMSTATE_STRUCT_VARRAY_POINTER_INT32(chan, PXA2xxDMAState, channels,
|
||||
vmstate_pxa2xx_dma_chan, PXA2xxDMAChannel),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static Property pxa2xx_dma_properties[] = {
|
||||
DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "PXA2xx DMA controller";
|
||||
dc->vmsd = &vmstate_pxa2xx_dma;
|
||||
device_class_set_props(dc, pxa2xx_dma_properties);
|
||||
dc->realize = pxa2xx_dma_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo pxa2xx_dma_info = {
|
||||
.name = TYPE_PXA2XX_DMA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PXA2xxDMAState),
|
||||
.instance_init = pxa2xx_dma_init,
|
||||
.class_init = pxa2xx_dma_class_init,
|
||||
};
|
||||
|
||||
static void pxa2xx_dma_register_types(void)
|
||||
{
|
||||
type_register_static(&pxa2xx_dma_info);
|
||||
}
|
||||
|
||||
type_init(pxa2xx_dma_register_types)
|
|
@ -23,3 +23,6 @@ config STM32L4X5_GPIO
|
|||
config PCF8574
|
||||
bool
|
||||
depends on I2C
|
||||
|
||||
config ZAURUS_SCOOP
|
||||
bool
|
||||
|
|
|
@ -5,7 +5,7 @@ system_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c'))
|
|||
system_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c'))
|
||||
system_ss.add(when: 'CONFIG_PCA9554', if_true: files('pca9554.c'))
|
||||
system_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c'))
|
||||
system_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
|
||||
system_ss.add(when: 'CONFIG_ZAURUS_SCOOP', if_true: files('zaurus.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
|
||||
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c'))
|
||||
|
|
|
@ -190,408 +190,6 @@ static void omap_gpio_reset(struct omap_gpio_s *s)
|
|||
s->pins = ~0;
|
||||
}
|
||||
|
||||
struct omap2_gpio_s {
|
||||
qemu_irq irq[2];
|
||||
qemu_irq wkup;
|
||||
qemu_irq *handler;
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint8_t revision;
|
||||
uint8_t config[2];
|
||||
uint32_t inputs;
|
||||
uint32_t outputs;
|
||||
uint32_t dir;
|
||||
uint32_t level[2];
|
||||
uint32_t edge[2];
|
||||
uint32_t mask[2];
|
||||
uint32_t wumask;
|
||||
uint32_t ints[2];
|
||||
uint32_t debounce;
|
||||
uint8_t delay;
|
||||
};
|
||||
|
||||
struct Omap2GpioState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
int mpu_model;
|
||||
void *iclk;
|
||||
void *fclk[6];
|
||||
int modulecount;
|
||||
struct omap2_gpio_s *modules;
|
||||
qemu_irq *handler;
|
||||
int autoidle;
|
||||
int gpo;
|
||||
};
|
||||
|
||||
/* General-Purpose Interface of OMAP2/3 */
|
||||
static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
|
||||
int line)
|
||||
{
|
||||
qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
|
||||
}
|
||||
|
||||
static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line)
|
||||
{
|
||||
if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */
|
||||
return;
|
||||
if (!(s->config[0] & (3 << 3))) /* Force Idle */
|
||||
return;
|
||||
if (!(s->wumask & (1 << line)))
|
||||
return;
|
||||
|
||||
qemu_irq_raise(s->wkup);
|
||||
}
|
||||
|
||||
static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,
|
||||
uint32_t diff)
|
||||
{
|
||||
int ln;
|
||||
|
||||
s->outputs ^= diff;
|
||||
diff &= ~s->dir;
|
||||
while ((ln = ctz32(diff)) != 32) {
|
||||
qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
|
||||
diff &= ~(1 << ln);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line)
|
||||
{
|
||||
s->ints[line] |= s->dir &
|
||||
((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));
|
||||
omap2_gpio_module_int_update(s, line);
|
||||
}
|
||||
|
||||
static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
|
||||
{
|
||||
s->ints[0] |= 1 << line;
|
||||
omap2_gpio_module_int_update(s, 0);
|
||||
s->ints[1] |= 1 << line;
|
||||
omap2_gpio_module_int_update(s, 1);
|
||||
omap2_gpio_module_wake(s, line);
|
||||
}
|
||||
|
||||
static void omap2_gpio_set(void *opaque, int line, int level)
|
||||
{
|
||||
Omap2GpioState *p = opaque;
|
||||
struct omap2_gpio_s *s = &p->modules[line >> 5];
|
||||
|
||||
line &= 31;
|
||||
if (level) {
|
||||
if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
|
||||
omap2_gpio_module_int(s, line);
|
||||
s->inputs |= 1 << line;
|
||||
} else {
|
||||
if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))
|
||||
omap2_gpio_module_int(s, line);
|
||||
s->inputs &= ~(1 << line);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap2_gpio_module_reset(struct omap2_gpio_s *s)
|
||||
{
|
||||
s->config[0] = 0;
|
||||
s->config[1] = 2;
|
||||
s->ints[0] = 0;
|
||||
s->ints[1] = 0;
|
||||
s->mask[0] = 0;
|
||||
s->mask[1] = 0;
|
||||
s->wumask = 0;
|
||||
s->dir = ~0;
|
||||
s->level[0] = 0;
|
||||
s->level[1] = 0;
|
||||
s->edge[0] = 0;
|
||||
s->edge[1] = 0;
|
||||
s->debounce = 0;
|
||||
s->delay = 0;
|
||||
}
|
||||
|
||||
static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr)
|
||||
{
|
||||
struct omap2_gpio_s *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* GPIO_REVISION */
|
||||
return s->revision;
|
||||
|
||||
case 0x10: /* GPIO_SYSCONFIG */
|
||||
return s->config[0];
|
||||
|
||||
case 0x14: /* GPIO_SYSSTATUS */
|
||||
return 0x01;
|
||||
|
||||
case 0x18: /* GPIO_IRQSTATUS1 */
|
||||
return s->ints[0];
|
||||
|
||||
case 0x1c: /* GPIO_IRQENABLE1 */
|
||||
case 0x60: /* GPIO_CLEARIRQENABLE1 */
|
||||
case 0x64: /* GPIO_SETIRQENABLE1 */
|
||||
return s->mask[0];
|
||||
|
||||
case 0x20: /* GPIO_WAKEUPENABLE */
|
||||
case 0x80: /* GPIO_CLEARWKUENA */
|
||||
case 0x84: /* GPIO_SETWKUENA */
|
||||
return s->wumask;
|
||||
|
||||
case 0x28: /* GPIO_IRQSTATUS2 */
|
||||
return s->ints[1];
|
||||
|
||||
case 0x2c: /* GPIO_IRQENABLE2 */
|
||||
case 0x70: /* GPIO_CLEARIRQENABLE2 */
|
||||
case 0x74: /* GPIO_SETIREQNEABLE2 */
|
||||
return s->mask[1];
|
||||
|
||||
case 0x30: /* GPIO_CTRL */
|
||||
return s->config[1];
|
||||
|
||||
case 0x34: /* GPIO_OE */
|
||||
return s->dir;
|
||||
|
||||
case 0x38: /* GPIO_DATAIN */
|
||||
return s->inputs;
|
||||
|
||||
case 0x3c: /* GPIO_DATAOUT */
|
||||
case 0x90: /* GPIO_CLEARDATAOUT */
|
||||
case 0x94: /* GPIO_SETDATAOUT */
|
||||
return s->outputs;
|
||||
|
||||
case 0x40: /* GPIO_LEVELDETECT0 */
|
||||
return s->level[0];
|
||||
|
||||
case 0x44: /* GPIO_LEVELDETECT1 */
|
||||
return s->level[1];
|
||||
|
||||
case 0x48: /* GPIO_RISINGDETECT */
|
||||
return s->edge[0];
|
||||
|
||||
case 0x4c: /* GPIO_FALLINGDETECT */
|
||||
return s->edge[1];
|
||||
|
||||
case 0x50: /* GPIO_DEBOUNCENABLE */
|
||||
return s->debounce;
|
||||
|
||||
case 0x54: /* GPIO_DEBOUNCINGTIME */
|
||||
return s->delay;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap2_gpio_module_write(void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
{
|
||||
struct omap2_gpio_s *s = opaque;
|
||||
uint32_t diff;
|
||||
int ln;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* GPIO_REVISION */
|
||||
case 0x14: /* GPIO_SYSSTATUS */
|
||||
case 0x38: /* GPIO_DATAIN */
|
||||
OMAP_RO_REG(addr);
|
||||
break;
|
||||
|
||||
case 0x10: /* GPIO_SYSCONFIG */
|
||||
if (((value >> 3) & 3) == 3) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Illegal IDLEMODE value: 3\n", __func__);
|
||||
}
|
||||
if (value & 2)
|
||||
omap2_gpio_module_reset(s);
|
||||
s->config[0] = value & 0x1d;
|
||||
break;
|
||||
|
||||
case 0x18: /* GPIO_IRQSTATUS1 */
|
||||
if (s->ints[0] & value) {
|
||||
s->ints[0] &= ~value;
|
||||
omap2_gpio_module_level_update(s, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1c: /* GPIO_IRQENABLE1 */
|
||||
s->mask[0] = value;
|
||||
omap2_gpio_module_int_update(s, 0);
|
||||
break;
|
||||
|
||||
case 0x20: /* GPIO_WAKEUPENABLE */
|
||||
s->wumask = value;
|
||||
break;
|
||||
|
||||
case 0x28: /* GPIO_IRQSTATUS2 */
|
||||
if (s->ints[1] & value) {
|
||||
s->ints[1] &= ~value;
|
||||
omap2_gpio_module_level_update(s, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2c: /* GPIO_IRQENABLE2 */
|
||||
s->mask[1] = value;
|
||||
omap2_gpio_module_int_update(s, 1);
|
||||
break;
|
||||
|
||||
case 0x30: /* GPIO_CTRL */
|
||||
s->config[1] = value & 7;
|
||||
break;
|
||||
|
||||
case 0x34: /* GPIO_OE */
|
||||
diff = s->outputs & (s->dir ^ value);
|
||||
s->dir = value;
|
||||
|
||||
value = s->outputs & ~s->dir;
|
||||
while ((ln = ctz32(diff)) != 32) {
|
||||
diff &= ~(1 << ln);
|
||||
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
||||
}
|
||||
|
||||
omap2_gpio_module_level_update(s, 0);
|
||||
omap2_gpio_module_level_update(s, 1);
|
||||
break;
|
||||
|
||||
case 0x3c: /* GPIO_DATAOUT */
|
||||
omap2_gpio_module_out_update(s, s->outputs ^ value);
|
||||
break;
|
||||
|
||||
case 0x40: /* GPIO_LEVELDETECT0 */
|
||||
s->level[0] = value;
|
||||
omap2_gpio_module_level_update(s, 0);
|
||||
omap2_gpio_module_level_update(s, 1);
|
||||
break;
|
||||
|
||||
case 0x44: /* GPIO_LEVELDETECT1 */
|
||||
s->level[1] = value;
|
||||
omap2_gpio_module_level_update(s, 0);
|
||||
omap2_gpio_module_level_update(s, 1);
|
||||
break;
|
||||
|
||||
case 0x48: /* GPIO_RISINGDETECT */
|
||||
s->edge[0] = value;
|
||||
break;
|
||||
|
||||
case 0x4c: /* GPIO_FALLINGDETECT */
|
||||
s->edge[1] = value;
|
||||
break;
|
||||
|
||||
case 0x50: /* GPIO_DEBOUNCENABLE */
|
||||
s->debounce = value;
|
||||
break;
|
||||
|
||||
case 0x54: /* GPIO_DEBOUNCINGTIME */
|
||||
s->delay = value;
|
||||
break;
|
||||
|
||||
case 0x60: /* GPIO_CLEARIRQENABLE1 */
|
||||
s->mask[0] &= ~value;
|
||||
omap2_gpio_module_int_update(s, 0);
|
||||
break;
|
||||
|
||||
case 0x64: /* GPIO_SETIRQENABLE1 */
|
||||
s->mask[0] |= value;
|
||||
omap2_gpio_module_int_update(s, 0);
|
||||
break;
|
||||
|
||||
case 0x70: /* GPIO_CLEARIRQENABLE2 */
|
||||
s->mask[1] &= ~value;
|
||||
omap2_gpio_module_int_update(s, 1);
|
||||
break;
|
||||
|
||||
case 0x74: /* GPIO_SETIREQNEABLE2 */
|
||||
s->mask[1] |= value;
|
||||
omap2_gpio_module_int_update(s, 1);
|
||||
break;
|
||||
|
||||
case 0x80: /* GPIO_CLEARWKUENA */
|
||||
s->wumask &= ~value;
|
||||
break;
|
||||
|
||||
case 0x84: /* GPIO_SETWKUENA */
|
||||
s->wumask |= value;
|
||||
break;
|
||||
|
||||
case 0x90: /* GPIO_CLEARDATAOUT */
|
||||
omap2_gpio_module_out_update(s, s->outputs & value);
|
||||
break;
|
||||
|
||||
case 0x94: /* GPIO_SETDATAOUT */
|
||||
omap2_gpio_module_out_update(s, ~s->outputs & value);
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t omap2_gpio_module_readp(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
|
||||
}
|
||||
|
||||
static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
uint32_t cur = 0;
|
||||
uint32_t mask = 0xffff;
|
||||
|
||||
if (size == 4) {
|
||||
omap2_gpio_module_write(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr & ~3) {
|
||||
case 0x00: /* GPIO_REVISION */
|
||||
case 0x14: /* GPIO_SYSSTATUS */
|
||||
case 0x38: /* GPIO_DATAIN */
|
||||
OMAP_RO_REG(addr);
|
||||
break;
|
||||
|
||||
case 0x10: /* GPIO_SYSCONFIG */
|
||||
case 0x1c: /* GPIO_IRQENABLE1 */
|
||||
case 0x20: /* GPIO_WAKEUPENABLE */
|
||||
case 0x2c: /* GPIO_IRQENABLE2 */
|
||||
case 0x30: /* GPIO_CTRL */
|
||||
case 0x34: /* GPIO_OE */
|
||||
case 0x3c: /* GPIO_DATAOUT */
|
||||
case 0x40: /* GPIO_LEVELDETECT0 */
|
||||
case 0x44: /* GPIO_LEVELDETECT1 */
|
||||
case 0x48: /* GPIO_RISINGDETECT */
|
||||
case 0x4c: /* GPIO_FALLINGDETECT */
|
||||
case 0x50: /* GPIO_DEBOUNCENABLE */
|
||||
case 0x54: /* GPIO_DEBOUNCINGTIME */
|
||||
cur = omap2_gpio_module_read(opaque, addr & ~3) &
|
||||
~(mask << ((addr & 3) << 3));
|
||||
|
||||
/* Fall through. */
|
||||
case 0x18: /* GPIO_IRQSTATUS1 */
|
||||
case 0x28: /* GPIO_IRQSTATUS2 */
|
||||
case 0x60: /* GPIO_CLEARIRQENABLE1 */
|
||||
case 0x64: /* GPIO_SETIRQENABLE1 */
|
||||
case 0x70: /* GPIO_CLEARIRQENABLE2 */
|
||||
case 0x74: /* GPIO_SETIREQNEABLE2 */
|
||||
case 0x80: /* GPIO_CLEARWKUENA */
|
||||
case 0x84: /* GPIO_SETWKUENA */
|
||||
case 0x90: /* GPIO_CLEARDATAOUT */
|
||||
case 0x94: /* GPIO_SETDATAOUT */
|
||||
value <<= (addr & 3) << 3;
|
||||
omap2_gpio_module_write(opaque, addr, cur | value);
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap2_gpio_module_ops = {
|
||||
.read = omap2_gpio_module_readp,
|
||||
.write = omap2_gpio_module_writep,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void omap_gpif_reset(DeviceState *dev)
|
||||
{
|
||||
Omap1GpioState *s = OMAP1_GPIO(dev);
|
||||
|
@ -599,81 +197,6 @@ static void omap_gpif_reset(DeviceState *dev)
|
|||
omap_gpio_reset(&s->omap1);
|
||||
}
|
||||
|
||||
static void omap2_gpif_reset(DeviceState *dev)
|
||||
{
|
||||
Omap2GpioState *s = OMAP2_GPIO(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->modulecount; i++) {
|
||||
omap2_gpio_module_reset(&s->modules[i]);
|
||||
}
|
||||
s->autoidle = 0;
|
||||
s->gpo = 0;
|
||||
}
|
||||
|
||||
static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
Omap2GpioState *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* IPGENERICOCPSPL_REVISION */
|
||||
return 0x18;
|
||||
|
||||
case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
|
||||
return s->autoidle;
|
||||
|
||||
case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
|
||||
return 0x01;
|
||||
|
||||
case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
|
||||
return 0x00;
|
||||
|
||||
case 0x40: /* IPGENERICOCPSPL_GPO */
|
||||
return s->gpo;
|
||||
|
||||
case 0x50: /* IPGENERICOCPSPL_GPI */
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap2_gpif_top_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
Omap2GpioState *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* IPGENERICOCPSPL_REVISION */
|
||||
case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
|
||||
case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
|
||||
case 0x50: /* IPGENERICOCPSPL_GPI */
|
||||
OMAP_RO_REG(addr);
|
||||
break;
|
||||
|
||||
case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
|
||||
if (value & (1 << 1)) /* SOFTRESET */
|
||||
omap2_gpif_reset(DEVICE(s));
|
||||
s->autoidle = value & 1;
|
||||
break;
|
||||
|
||||
case 0x40: /* IPGENERICOCPSPL_GPO */
|
||||
s->gpo = value & 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap2_gpif_top_ops = {
|
||||
.read = omap2_gpif_top_read,
|
||||
.write = omap2_gpif_top_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void omap_gpio_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
@ -697,51 +220,6 @@ static void omap_gpio_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static void omap2_gpio_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
Omap2GpioState *s = OMAP2_GPIO(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
int i;
|
||||
|
||||
if (!s->iclk) {
|
||||
error_setg(errp, "omap2-gpio: iclk not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
s->modulecount = s->mpu_model < omap2430 ? 4
|
||||
: s->mpu_model < omap3430 ? 5
|
||||
: 6;
|
||||
|
||||
if (s->mpu_model < omap3430) {
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), &omap2_gpif_top_ops, s,
|
||||
"omap2.gpio", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
s->modules = g_new0(struct omap2_gpio_s, s->modulecount);
|
||||
s->handler = g_new0(qemu_irq, s->modulecount * 32);
|
||||
qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32);
|
||||
qdev_init_gpio_out(dev, s->handler, s->modulecount * 32);
|
||||
|
||||
for (i = 0; i < s->modulecount; i++) {
|
||||
struct omap2_gpio_s *m = &s->modules[i];
|
||||
|
||||
if (!s->fclk[i]) {
|
||||
error_setg(errp, "omap2-gpio: fclk%d not connected", i);
|
||||
return;
|
||||
}
|
||||
|
||||
m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
|
||||
m->handler = &s->handler[i * 32];
|
||||
sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */
|
||||
sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */
|
||||
sysbus_init_irq(sbd, &m->wkup);
|
||||
memory_region_init_io(&m->iomem, OBJECT(dev), &omap2_gpio_module_ops, m,
|
||||
"omap.gpio-module", 0x1000);
|
||||
sysbus_init_mmio(sbd, &m->iomem);
|
||||
}
|
||||
}
|
||||
|
||||
void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk)
|
||||
{
|
||||
gpio->clk = clk;
|
||||
|
@ -771,44 +249,9 @@ static const TypeInfo omap_gpio_info = {
|
|||
.class_init = omap_gpio_class_init,
|
||||
};
|
||||
|
||||
void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk)
|
||||
{
|
||||
gpio->iclk = clk;
|
||||
}
|
||||
|
||||
void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk)
|
||||
{
|
||||
assert(i <= 5);
|
||||
gpio->fclk[i] = clk;
|
||||
}
|
||||
|
||||
static Property omap2_gpio_properties[] = {
|
||||
DEFINE_PROP_INT32("mpu_model", Omap2GpioState, mpu_model, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void omap2_gpio_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = omap2_gpio_realize;
|
||||
device_class_set_legacy_reset(dc, omap2_gpif_reset);
|
||||
device_class_set_props(dc, omap2_gpio_properties);
|
||||
/* Reason: pointer properties "iclk", "fclk0", ..., "fclk5" */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo omap2_gpio_info = {
|
||||
.name = TYPE_OMAP2_GPIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Omap2GpioState),
|
||||
.class_init = omap2_gpio_class_init,
|
||||
};
|
||||
|
||||
static void omap_gpio_register_types(void)
|
||||
{
|
||||
type_register_static(&omap_gpio_info);
|
||||
type_register_static(&omap2_gpio_info);
|
||||
}
|
||||
|
||||
type_init(omap_gpio_register_types)
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
config ADB
|
||||
bool
|
||||
|
||||
config ADS7846
|
||||
bool
|
||||
|
||||
config LM832X
|
||||
bool
|
||||
depends on I2C
|
||||
|
||||
config PCKBD
|
||||
bool
|
||||
select PS2
|
||||
|
@ -23,9 +16,6 @@ config PS2
|
|||
config STELLARIS_GAMEPAD
|
||||
bool
|
||||
|
||||
config TSC2005
|
||||
bool
|
||||
|
||||
config VIRTIO_INPUT
|
||||
bool
|
||||
default y
|
||||
|
@ -41,8 +31,5 @@ config VHOST_USER_INPUT
|
|||
default y
|
||||
depends on VIRTIO_INPUT && VHOST_USER
|
||||
|
||||
config TSC210X
|
||||
bool
|
||||
|
||||
config LASIPS2
|
||||
select PS2
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* TI ADS7846 / TSC2046 chip emulation.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/module.h"
|
||||
#include "ui/console.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
struct ADS7846State {
|
||||
SSIPeripheral ssidev;
|
||||
qemu_irq interrupt;
|
||||
|
||||
int input[8];
|
||||
int pressure;
|
||||
int noise;
|
||||
|
||||
int cycle;
|
||||
int output;
|
||||
};
|
||||
|
||||
#define TYPE_ADS7846 "ads7846"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(ADS7846State, ADS7846)
|
||||
|
||||
/* Control-byte bitfields */
|
||||
#define CB_PD0 (1 << 0)
|
||||
#define CB_PD1 (1 << 1)
|
||||
#define CB_SER (1 << 2)
|
||||
#define CB_MODE (1 << 3)
|
||||
#define CB_A0 (1 << 4)
|
||||
#define CB_A1 (1 << 5)
|
||||
#define CB_A2 (1 << 6)
|
||||
#define CB_START (1 << 7)
|
||||
|
||||
#define X_AXIS_DMAX 3470
|
||||
#define X_AXIS_MIN 290
|
||||
#define Y_AXIS_DMAX 3450
|
||||
#define Y_AXIS_MIN 200
|
||||
|
||||
#define ADS_VBAT 2000
|
||||
#define ADS_VAUX 2000
|
||||
#define ADS_TEMP0 2000
|
||||
#define ADS_TEMP1 3000
|
||||
#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
|
||||
#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
|
||||
#define ADS_Z1POS(x, y) 600
|
||||
#define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y))
|
||||
|
||||
static void ads7846_int_update(ADS7846State *s)
|
||||
{
|
||||
if (s->interrupt)
|
||||
qemu_set_irq(s->interrupt, s->pressure == 0);
|
||||
}
|
||||
|
||||
static uint32_t ads7846_transfer(SSIPeripheral *dev, uint32_t value)
|
||||
{
|
||||
ADS7846State *s = ADS7846(dev);
|
||||
|
||||
switch (s->cycle ++) {
|
||||
case 0:
|
||||
if (!(value & CB_START)) {
|
||||
s->cycle = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
s->output = s->input[(value >> 4) & 7];
|
||||
|
||||
/* Imitate the ADC noise, some drivers expect this. */
|
||||
s->noise = (s->noise + 3) & 7;
|
||||
switch ((value >> 4) & 7) {
|
||||
case 1: s->output += s->noise ^ 2; break;
|
||||
case 3: s->output += s->noise ^ 0; break;
|
||||
case 4: s->output += s->noise ^ 7; break;
|
||||
case 5: s->output += s->noise ^ 5; break;
|
||||
}
|
||||
|
||||
if (value & CB_MODE)
|
||||
s->output >>= 4; /* 8 bits instead of 12 */
|
||||
|
||||
break;
|
||||
case 1:
|
||||
s->cycle = 0;
|
||||
break;
|
||||
}
|
||||
return s->output;
|
||||
}
|
||||
|
||||
static void ads7846_ts_event(void *opaque,
|
||||
int x, int y, int z, int buttons_state)
|
||||
{
|
||||
ADS7846State *s = opaque;
|
||||
|
||||
if (buttons_state) {
|
||||
x = 0x7fff - x;
|
||||
s->input[1] = ADS_XPOS(x, y);
|
||||
s->input[3] = ADS_Z1POS(x, y);
|
||||
s->input[4] = ADS_Z2POS(x, y);
|
||||
s->input[5] = ADS_YPOS(x, y);
|
||||
}
|
||||
|
||||
if (s->pressure == !buttons_state) {
|
||||
s->pressure = !!buttons_state;
|
||||
|
||||
ads7846_int_update(s);
|
||||
}
|
||||
}
|
||||
|
||||
static int ads7856_post_load(void *opaque, int version_id)
|
||||
{
|
||||
ADS7846State *s = opaque;
|
||||
|
||||
s->pressure = 0;
|
||||
ads7846_int_update(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ads7846 = {
|
||||
.name = "ads7846",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = ads7856_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_SSI_PERIPHERAL(ssidev, ADS7846State),
|
||||
VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
|
||||
VMSTATE_INT32(noise, ADS7846State),
|
||||
VMSTATE_INT32(cycle, ADS7846State),
|
||||
VMSTATE_INT32(output, ADS7846State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void ads7846_realize(SSIPeripheral *d, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(d);
|
||||
ADS7846State *s = ADS7846(d);
|
||||
|
||||
qdev_init_gpio_out(dev, &s->interrupt, 1);
|
||||
|
||||
s->input[0] = ADS_TEMP0; /* TEMP0 */
|
||||
s->input[2] = ADS_VBAT; /* VBAT */
|
||||
s->input[6] = ADS_VAUX; /* VAUX */
|
||||
s->input[7] = ADS_TEMP1; /* TEMP1 */
|
||||
|
||||
/* We want absolute coordinates */
|
||||
qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
|
||||
"QEMU ADS7846-driven Touchscreen");
|
||||
|
||||
ads7846_int_update(s);
|
||||
|
||||
vmstate_register_any(NULL, &vmstate_ads7846, s);
|
||||
}
|
||||
|
||||
static void ads7846_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
|
||||
|
||||
k->realize = ads7846_realize;
|
||||
k->transfer = ads7846_transfer;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo ads7846_info = {
|
||||
.name = TYPE_ADS7846,
|
||||
.parent = TYPE_SSI_PERIPHERAL,
|
||||
.instance_size = sizeof(ADS7846State),
|
||||
.class_init = ads7846_class_init,
|
||||
};
|
||||
|
||||
static void ads7846_register_types(void)
|
||||
{
|
||||
type_register_static(&ads7846_info);
|
||||
}
|
||||
|
||||
type_init(ads7846_register_types)
|
|
@ -1,528 +0,0 @@
|
|||
/*
|
||||
* National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/input/lm832x.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "ui/console.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LM823KbdState, LM8323)
|
||||
|
||||
struct LM823KbdState {
|
||||
I2CSlave parent_obj;
|
||||
|
||||
uint8_t i2c_dir;
|
||||
uint8_t i2c_cycle;
|
||||
uint8_t reg;
|
||||
|
||||
qemu_irq nirq;
|
||||
uint16_t model;
|
||||
|
||||
struct {
|
||||
qemu_irq out[2];
|
||||
int in[2][2];
|
||||
} mux;
|
||||
|
||||
uint8_t config;
|
||||
uint8_t status;
|
||||
uint8_t acttime;
|
||||
uint8_t error;
|
||||
uint8_t clock;
|
||||
|
||||
struct {
|
||||
uint16_t pull;
|
||||
uint16_t mask;
|
||||
uint16_t dir;
|
||||
uint16_t level;
|
||||
qemu_irq out[16];
|
||||
} gpio;
|
||||
|
||||
struct {
|
||||
uint8_t dbnctime;
|
||||
uint8_t size;
|
||||
uint8_t start;
|
||||
uint8_t len;
|
||||
uint8_t fifo[16];
|
||||
} kbd;
|
||||
|
||||
struct {
|
||||
uint16_t file[256];
|
||||
uint8_t faddr;
|
||||
uint8_t addr[3];
|
||||
QEMUTimer *tm[3];
|
||||
} pwm;
|
||||
};
|
||||
|
||||
#define INT_KEYPAD (1 << 0)
|
||||
#define INT_ERROR (1 << 3)
|
||||
#define INT_NOINIT (1 << 4)
|
||||
#define INT_PWMEND(n) (1 << (5 + n))
|
||||
|
||||
#define ERR_BADPAR (1 << 0)
|
||||
#define ERR_CMDUNK (1 << 1)
|
||||
#define ERR_KEYOVR (1 << 2)
|
||||
#define ERR_FIFOOVR (1 << 6)
|
||||
|
||||
static void lm_kbd_irq_update(LM823KbdState *s)
|
||||
{
|
||||
qemu_set_irq(s->nirq, !s->status);
|
||||
}
|
||||
|
||||
static void lm_kbd_gpio_update(LM823KbdState *s)
|
||||
{
|
||||
}
|
||||
|
||||
static void lm_kbd_reset(DeviceState *dev)
|
||||
{
|
||||
LM823KbdState *s = LM8323(dev);
|
||||
|
||||
s->config = 0x80;
|
||||
s->status = INT_NOINIT;
|
||||
s->acttime = 125;
|
||||
s->kbd.dbnctime = 3;
|
||||
s->kbd.size = 0x33;
|
||||
s->clock = 0x08;
|
||||
|
||||
lm_kbd_irq_update(s);
|
||||
lm_kbd_gpio_update(s);
|
||||
}
|
||||
|
||||
static void lm_kbd_error(LM823KbdState *s, int err)
|
||||
{
|
||||
s->error |= err;
|
||||
s->status |= INT_ERROR;
|
||||
lm_kbd_irq_update(s);
|
||||
}
|
||||
|
||||
static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
|
||||
{
|
||||
}
|
||||
|
||||
static void lm_kbd_pwm_start(LM823KbdState *s, int line)
|
||||
{
|
||||
lm_kbd_pwm_tick(s, line);
|
||||
}
|
||||
|
||||
static void lm_kbd_pwm0_tick(void *opaque)
|
||||
{
|
||||
lm_kbd_pwm_tick(opaque, 0);
|
||||
}
|
||||
static void lm_kbd_pwm1_tick(void *opaque)
|
||||
{
|
||||
lm_kbd_pwm_tick(opaque, 1);
|
||||
}
|
||||
static void lm_kbd_pwm2_tick(void *opaque)
|
||||
{
|
||||
lm_kbd_pwm_tick(opaque, 2);
|
||||
}
|
||||
|
||||
enum {
|
||||
LM832x_CMD_READ_ID = 0x80, /* Read chip ID. */
|
||||
LM832x_CMD_WRITE_CFG = 0x81, /* Set configuration item. */
|
||||
LM832x_CMD_READ_INT = 0x82, /* Get interrupt status. */
|
||||
LM832x_CMD_RESET = 0x83, /* Reset, same as external one */
|
||||
LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */
|
||||
LM832x_CMD_WRITE_PORT_SEL = 0x85, /* Select GPIO in/out. */
|
||||
LM832x_CMD_WRITE_PORT_STATE = 0x86, /* Set GPIO pull-up/down. */
|
||||
LM832x_CMD_READ_PORT_SEL = 0x87, /* Get GPIO in/out. */
|
||||
LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */
|
||||
LM832x_CMD_READ_FIFO = 0x89, /* Read byte from FIFO. */
|
||||
LM832x_CMD_RPT_READ_FIFO = 0x8a, /* Read FIFO (no increment). */
|
||||
LM832x_CMD_SET_ACTIVE = 0x8b, /* Set active time. */
|
||||
LM832x_CMD_READ_ERROR = 0x8c, /* Get error status. */
|
||||
LM832x_CMD_READ_ROTATOR = 0x8e, /* Read rotator status. */
|
||||
LM832x_CMD_SET_DEBOUNCE = 0x8f, /* Set debouncing time. */
|
||||
LM832x_CMD_SET_KEY_SIZE = 0x90, /* Set keypad size. */
|
||||
LM832x_CMD_READ_KEY_SIZE = 0x91, /* Get keypad size. */
|
||||
LM832x_CMD_READ_CFG = 0x92, /* Get configuration item. */
|
||||
LM832x_CMD_WRITE_CLOCK = 0x93, /* Set clock config. */
|
||||
LM832x_CMD_READ_CLOCK = 0x94, /* Get clock config. */
|
||||
LM832x_CMD_PWM_WRITE = 0x95, /* Write PWM script. */
|
||||
LM832x_CMD_PWM_START = 0x96, /* Start PWM engine. */
|
||||
LM832x_CMD_PWM_STOP = 0x97, /* Stop PWM engine. */
|
||||
LM832x_GENERAL_ERROR = 0xff, /* There was one error.
|
||||
Previously was represented by -1
|
||||
This is not a command */
|
||||
};
|
||||
|
||||
#define LM832x_MAX_KPX 8
|
||||
#define LM832x_MAX_KPY 12
|
||||
|
||||
static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case LM832x_CMD_READ_ID:
|
||||
ret = 0x0400;
|
||||
break;
|
||||
|
||||
case LM832x_CMD_READ_INT:
|
||||
ret = s->status;
|
||||
if (!(s->status & INT_NOINIT)) {
|
||||
s->status = 0;
|
||||
lm_kbd_irq_update(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case LM832x_CMD_READ_PORT_SEL:
|
||||
ret = s->gpio.dir;
|
||||
break;
|
||||
case LM832x_CMD_READ_PORT_STATE:
|
||||
ret = s->gpio.mask;
|
||||
break;
|
||||
|
||||
case LM832x_CMD_READ_FIFO:
|
||||
if (s->kbd.len <= 1)
|
||||
return 0x00;
|
||||
|
||||
/* Example response from the two commands after a INT_KEYPAD
|
||||
* interrupt caused by the key 0x3c being pressed:
|
||||
* RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
|
||||
* READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
|
||||
* RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
|
||||
*
|
||||
* 55 is the code of the key release event serviced in the previous
|
||||
* interrupt handling.
|
||||
*
|
||||
* TODO: find out whether the FIFO is advanced a single character
|
||||
* before reading every byte or the whole size of the FIFO at the
|
||||
* last LM832x_CMD_READ_FIFO. This affects LM832x_CMD_RPT_READ_FIFO
|
||||
* output in cases where there are more than one event in the FIFO.
|
||||
* Assume 0xbc and 0x3c events are in the FIFO:
|
||||
* RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
|
||||
* READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
|
||||
* Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
|
||||
*/
|
||||
s->kbd.start ++;
|
||||
s->kbd.start &= sizeof(s->kbd.fifo) - 1;
|
||||
s->kbd.len --;
|
||||
|
||||
return s->kbd.fifo[s->kbd.start];
|
||||
case LM832x_CMD_RPT_READ_FIFO:
|
||||
if (byte >= s->kbd.len)
|
||||
return 0x00;
|
||||
|
||||
return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
|
||||
|
||||
case LM832x_CMD_READ_ERROR:
|
||||
return s->error;
|
||||
|
||||
case LM832x_CMD_READ_ROTATOR:
|
||||
return 0;
|
||||
|
||||
case LM832x_CMD_READ_KEY_SIZE:
|
||||
return s->kbd.size;
|
||||
|
||||
case LM832x_CMD_READ_CFG:
|
||||
return s->config & 0xf;
|
||||
|
||||
case LM832x_CMD_READ_CLOCK:
|
||||
return (s->clock & 0xfc) | 2;
|
||||
|
||||
default:
|
||||
lm_kbd_error(s, ERR_CMDUNK);
|
||||
fprintf(stderr, "%s: unknown command %02x\n", __func__, reg);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
return ret >> (byte << 3);
|
||||
}
|
||||
|
||||
static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
|
||||
{
|
||||
switch (reg) {
|
||||
case LM832x_CMD_WRITE_CFG:
|
||||
s->config = value;
|
||||
/* This must be done whenever s->mux.in is updated (never). */
|
||||
if ((s->config >> 1) & 1) /* MUX1EN */
|
||||
qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
|
||||
if ((s->config >> 3) & 1) /* MUX2EN */
|
||||
qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
|
||||
/* TODO: check that this is issued only following the chip reset
|
||||
* and not in the middle of operation and that it is followed by
|
||||
* the GPIO ports re-resablishing through WRITE_PORT_SEL and
|
||||
* WRITE_PORT_STATE (using a timer perhaps) and otherwise output
|
||||
* warnings. */
|
||||
s->status = 0;
|
||||
lm_kbd_irq_update(s);
|
||||
s->kbd.len = 0;
|
||||
s->kbd.start = 0;
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
break;
|
||||
|
||||
case LM832x_CMD_RESET:
|
||||
if (value == 0xaa)
|
||||
lm_kbd_reset(DEVICE(s));
|
||||
else
|
||||
lm_kbd_error(s, ERR_BADPAR);
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
break;
|
||||
|
||||
case LM823x_CMD_WRITE_PULL_DOWN:
|
||||
if (!byte)
|
||||
s->gpio.pull = value;
|
||||
else {
|
||||
s->gpio.pull |= value << 8;
|
||||
lm_kbd_gpio_update(s);
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
}
|
||||
break;
|
||||
case LM832x_CMD_WRITE_PORT_SEL:
|
||||
if (!byte)
|
||||
s->gpio.dir = value;
|
||||
else {
|
||||
s->gpio.dir |= value << 8;
|
||||
lm_kbd_gpio_update(s);
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
}
|
||||
break;
|
||||
case LM832x_CMD_WRITE_PORT_STATE:
|
||||
if (!byte)
|
||||
s->gpio.mask = value;
|
||||
else {
|
||||
s->gpio.mask |= value << 8;
|
||||
lm_kbd_gpio_update(s);
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case LM832x_CMD_SET_ACTIVE:
|
||||
s->acttime = value;
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
break;
|
||||
|
||||
case LM832x_CMD_SET_DEBOUNCE:
|
||||
s->kbd.dbnctime = value;
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
if (!value)
|
||||
lm_kbd_error(s, ERR_BADPAR);
|
||||
break;
|
||||
|
||||
case LM832x_CMD_SET_KEY_SIZE:
|
||||
s->kbd.size = value;
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
if (
|
||||
(value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
|
||||
(value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
|
||||
lm_kbd_error(s, ERR_BADPAR);
|
||||
break;
|
||||
|
||||
case LM832x_CMD_WRITE_CLOCK:
|
||||
s->clock = value;
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
if ((value & 3) && (value & 3) != 3) {
|
||||
lm_kbd_error(s, ERR_BADPAR);
|
||||
fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
|
||||
__func__);
|
||||
}
|
||||
/* TODO: Validate that the command is only issued once */
|
||||
break;
|
||||
|
||||
case LM832x_CMD_PWM_WRITE:
|
||||
if (byte == 0) {
|
||||
if (!(value & 3) || (value >> 2) > 59) {
|
||||
lm_kbd_error(s, ERR_BADPAR);
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
s->pwm.faddr = value;
|
||||
s->pwm.file[s->pwm.faddr] = 0;
|
||||
} else if (byte == 1) {
|
||||
s->pwm.file[s->pwm.faddr] |= value << 8;
|
||||
} else if (byte == 2) {
|
||||
s->pwm.file[s->pwm.faddr] |= value << 0;
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
}
|
||||
break;
|
||||
case LM832x_CMD_PWM_START:
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
if (!(value & 3) || (value >> 2) > 59) {
|
||||
lm_kbd_error(s, ERR_BADPAR);
|
||||
break;
|
||||
}
|
||||
|
||||
s->pwm.addr[(value & 3) - 1] = value >> 2;
|
||||
lm_kbd_pwm_start(s, (value & 3) - 1);
|
||||
break;
|
||||
case LM832x_CMD_PWM_STOP:
|
||||
s->reg = LM832x_GENERAL_ERROR;
|
||||
if (!(value & 3)) {
|
||||
lm_kbd_error(s, ERR_BADPAR);
|
||||
break;
|
||||
}
|
||||
|
||||
timer_del(s->pwm.tm[(value & 3) - 1]);
|
||||
break;
|
||||
|
||||
case LM832x_GENERAL_ERROR:
|
||||
lm_kbd_error(s, ERR_BADPAR);
|
||||
break;
|
||||
default:
|
||||
lm_kbd_error(s, ERR_CMDUNK);
|
||||
fprintf(stderr, "%s: unknown command %02x\n", __func__, reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
LM823KbdState *s = LM8323(i2c);
|
||||
|
||||
switch (event) {
|
||||
case I2C_START_RECV:
|
||||
case I2C_START_SEND:
|
||||
s->i2c_cycle = 0;
|
||||
s->i2c_dir = (event == I2C_START_SEND);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t lm_i2c_rx(I2CSlave *i2c)
|
||||
{
|
||||
LM823KbdState *s = LM8323(i2c);
|
||||
|
||||
return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
|
||||
}
|
||||
|
||||
static int lm_i2c_tx(I2CSlave *i2c, uint8_t data)
|
||||
{
|
||||
LM823KbdState *s = LM8323(i2c);
|
||||
|
||||
if (!s->i2c_cycle)
|
||||
s->reg = data;
|
||||
else
|
||||
lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
|
||||
s->i2c_cycle ++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm_kbd_post_load(void *opaque, int version_id)
|
||||
{
|
||||
LM823KbdState *s = opaque;
|
||||
|
||||
lm_kbd_irq_update(s);
|
||||
lm_kbd_gpio_update(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lm_kbd = {
|
||||
.name = "LM8323",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.post_load = lm_kbd_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_I2C_SLAVE(parent_obj, LM823KbdState),
|
||||
VMSTATE_UINT8(i2c_dir, LM823KbdState),
|
||||
VMSTATE_UINT8(i2c_cycle, LM823KbdState),
|
||||
VMSTATE_UINT8(reg, LM823KbdState),
|
||||
VMSTATE_UINT8(config, LM823KbdState),
|
||||
VMSTATE_UINT8(status, LM823KbdState),
|
||||
VMSTATE_UINT8(acttime, LM823KbdState),
|
||||
VMSTATE_UINT8(error, LM823KbdState),
|
||||
VMSTATE_UINT8(clock, LM823KbdState),
|
||||
VMSTATE_UINT16(gpio.pull, LM823KbdState),
|
||||
VMSTATE_UINT16(gpio.mask, LM823KbdState),
|
||||
VMSTATE_UINT16(gpio.dir, LM823KbdState),
|
||||
VMSTATE_UINT16(gpio.level, LM823KbdState),
|
||||
VMSTATE_UINT8(kbd.dbnctime, LM823KbdState),
|
||||
VMSTATE_UINT8(kbd.size, LM823KbdState),
|
||||
VMSTATE_UINT8(kbd.start, LM823KbdState),
|
||||
VMSTATE_UINT8(kbd.len, LM823KbdState),
|
||||
VMSTATE_BUFFER(kbd.fifo, LM823KbdState),
|
||||
VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
|
||||
VMSTATE_UINT8(pwm.faddr, LM823KbdState),
|
||||
VMSTATE_BUFFER(pwm.addr, LM823KbdState),
|
||||
VMSTATE_TIMER_PTR_ARRAY(pwm.tm, LM823KbdState, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void lm8323_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
LM823KbdState *s = LM8323(dev);
|
||||
|
||||
s->model = 0x8323;
|
||||
s->pwm.tm[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm0_tick, s);
|
||||
s->pwm.tm[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm1_tick, s);
|
||||
s->pwm.tm[2] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm2_tick, s);
|
||||
qdev_init_gpio_out(dev, &s->nirq, 1);
|
||||
}
|
||||
|
||||
void lm832x_key_event(DeviceState *dev, int key, int state)
|
||||
{
|
||||
LM823KbdState *s = LM8323(dev);
|
||||
|
||||
if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
|
||||
return;
|
||||
|
||||
if (s->kbd.len >= sizeof(s->kbd.fifo)) {
|
||||
lm_kbd_error(s, ERR_FIFOOVR);
|
||||
return;
|
||||
}
|
||||
|
||||
s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
|
||||
key | (state << 7);
|
||||
|
||||
/* We never set ERR_KEYOVR because we support multiple keys fine. */
|
||||
s->status |= INT_KEYPAD;
|
||||
lm_kbd_irq_update(s);
|
||||
}
|
||||
|
||||
static void lm8323_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
device_class_set_legacy_reset(dc, lm_kbd_reset);
|
||||
dc->realize = lm8323_realize;
|
||||
k->event = lm_i2c_event;
|
||||
k->recv = lm_i2c_rx;
|
||||
k->send = lm_i2c_tx;
|
||||
dc->vmsd = &vmstate_lm_kbd;
|
||||
}
|
||||
|
||||
static const TypeInfo lm8323_info = {
|
||||
.name = TYPE_LM8323,
|
||||
.parent = TYPE_I2C_SLAVE,
|
||||
.instance_size = sizeof(LM823KbdState),
|
||||
.class_init = lm8323_class_init,
|
||||
};
|
||||
|
||||
static void lm832x_register_types(void)
|
||||
{
|
||||
type_register_static(&lm8323_info);
|
||||
}
|
||||
|
||||
type_init(lm832x_register_types)
|
|
@ -1,17 +1,12 @@
|
|||
system_ss.add(files('hid.c'))
|
||||
system_ss.add(when: 'CONFIG_ADB', if_true: files('adb.c', 'adb-mouse.c', 'adb-kbd.c'))
|
||||
system_ss.add(when: 'CONFIG_ADS7846', if_true: files('ads7846.c'))
|
||||
system_ss.add(when: 'CONFIG_LM832X', if_true: files('lm832x.c'))
|
||||
system_ss.add(when: 'CONFIG_PCKBD', if_true: files('pckbd.c'))
|
||||
system_ss.add(when: 'CONFIG_PL050', if_true: files('pl050.c'))
|
||||
system_ss.add(when: 'CONFIG_PS2', if_true: files('ps2.c'))
|
||||
system_ss.add(when: 'CONFIG_STELLARIS_GAMEPAD', if_true: files('stellaris_gamepad.c'))
|
||||
system_ss.add(when: 'CONFIG_TSC2005', if_true: files('tsc2005.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input.c'))
|
||||
system_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-hid.c'))
|
||||
system_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_keypad.c'))
|
||||
system_ss.add(when: 'CONFIG_TSC210X', if_true: files('tsc210x.c'))
|
||||
system_ss.add(when: 'CONFIG_LASIPS2', if_true: files('lasips2.c'))
|
||||
|
|
|
@ -1,331 +0,0 @@
|
|||
/*
|
||||
* Intel PXA27X Keypad Controller emulation.
|
||||
*
|
||||
* Copyright (c) 2007 MontaVista Software, Inc
|
||||
* Written by Armin Kuster <akuster@kama-aina.net>
|
||||
* or <Akuster@mvista.com>
|
||||
*
|
||||
* This code is licensed under the GPLv2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "ui/console.h"
|
||||
|
||||
/*
|
||||
* Keypad
|
||||
*/
|
||||
#define KPC 0x00 /* Keypad Interface Control register */
|
||||
#define KPDK 0x08 /* Keypad Interface Direct Key register */
|
||||
#define KPREC 0x10 /* Keypad Interface Rotary Encoder register */
|
||||
#define KPMK 0x18 /* Keypad Interface Matrix Key register */
|
||||
#define KPAS 0x20 /* Keypad Interface Automatic Scan register */
|
||||
#define KPASMKP0 0x28 /* Keypad Interface Automatic Scan Multiple
|
||||
Key Presser register 0 */
|
||||
#define KPASMKP1 0x30 /* Keypad Interface Automatic Scan Multiple
|
||||
Key Presser register 1 */
|
||||
#define KPASMKP2 0x38 /* Keypad Interface Automatic Scan Multiple
|
||||
Key Presser register 2 */
|
||||
#define KPASMKP3 0x40 /* Keypad Interface Automatic Scan Multiple
|
||||
Key Presser register 3 */
|
||||
#define KPKDI 0x48 /* Keypad Interface Key Debounce Interval
|
||||
register */
|
||||
|
||||
/* Keypad defines */
|
||||
#define KPC_AS (0x1 << 30) /* Automatic Scan bit */
|
||||
#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
|
||||
#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
|
||||
#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
|
||||
#define KPC_MS7 (0x1 << 20) /* Matrix scan line 7 */
|
||||
#define KPC_MS6 (0x1 << 19) /* Matrix scan line 6 */
|
||||
#define KPC_MS5 (0x1 << 18) /* Matrix scan line 5 */
|
||||
#define KPC_MS4 (0x1 << 17) /* Matrix scan line 4 */
|
||||
#define KPC_MS3 (0x1 << 16) /* Matrix scan line 3 */
|
||||
#define KPC_MS2 (0x1 << 15) /* Matrix scan line 2 */
|
||||
#define KPC_MS1 (0x1 << 14) /* Matrix scan line 1 */
|
||||
#define KPC_MS0 (0x1 << 13) /* Matrix scan line 0 */
|
||||
#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
|
||||
#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
|
||||
#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
|
||||
#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
|
||||
#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
|
||||
#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
|
||||
#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
|
||||
#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
|
||||
#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
|
||||
|
||||
#define KPDK_DKP (0x1 << 31)
|
||||
#define KPDK_DK7 (0x1 << 7)
|
||||
#define KPDK_DK6 (0x1 << 6)
|
||||
#define KPDK_DK5 (0x1 << 5)
|
||||
#define KPDK_DK4 (0x1 << 4)
|
||||
#define KPDK_DK3 (0x1 << 3)
|
||||
#define KPDK_DK2 (0x1 << 2)
|
||||
#define KPDK_DK1 (0x1 << 1)
|
||||
#define KPDK_DK0 (0x1 << 0)
|
||||
|
||||
#define KPREC_OF1 (0x1 << 31)
|
||||
#define KPREC_UF1 (0x1 << 30)
|
||||
#define KPREC_OF0 (0x1 << 15)
|
||||
#define KPREC_UF0 (0x1 << 14)
|
||||
|
||||
#define KPMK_MKP (0x1 << 31)
|
||||
#define KPAS_SO (0x1 << 31)
|
||||
#define KPASMKPx_SO (0x1 << 31)
|
||||
|
||||
|
||||
#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
|
||||
|
||||
#define PXAKBD_MAXROW 8
|
||||
#define PXAKBD_MAXCOL 8
|
||||
|
||||
struct PXA2xxKeyPadState {
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
const struct keymap *map;
|
||||
int pressed_cnt;
|
||||
int alt_code;
|
||||
|
||||
uint32_t kpc;
|
||||
uint32_t kpdk;
|
||||
uint32_t kprec;
|
||||
uint32_t kpmk;
|
||||
uint32_t kpas;
|
||||
uint32_t kpasmkp[4];
|
||||
uint32_t kpkdi;
|
||||
};
|
||||
|
||||
static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
*col = i * 2;
|
||||
for (*row = 0; *row < 8; (*row)++) {
|
||||
if (kp->kpasmkp[i] & (1 << *row))
|
||||
return;
|
||||
}
|
||||
*col = i * 2 + 1;
|
||||
for (*row = 0; *row < 8; (*row)++) {
|
||||
if (kp->kpasmkp[i] & (1 << (*row + 16)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
|
||||
{
|
||||
int row, col, rel, assert_irq = 0;
|
||||
uint32_t val;
|
||||
|
||||
if (keycode == 0xe0) {
|
||||
kp->alt_code = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
|
||||
return;
|
||||
|
||||
rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
|
||||
keycode &= ~0x80; /* strip qemu key release bit */
|
||||
if (kp->alt_code) {
|
||||
keycode |= 0x80;
|
||||
kp->alt_code = 0;
|
||||
}
|
||||
|
||||
row = kp->map[keycode].row;
|
||||
col = kp->map[keycode].column;
|
||||
if (row == -1 || col == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
val = KPASMKPx_MKC(row, col);
|
||||
if (rel) {
|
||||
if (kp->kpasmkp[col / 2] & val) {
|
||||
kp->kpasmkp[col / 2] &= ~val;
|
||||
kp->pressed_cnt--;
|
||||
assert_irq = 1;
|
||||
}
|
||||
} else {
|
||||
if (!(kp->kpasmkp[col / 2] & val)) {
|
||||
kp->kpasmkp[col / 2] |= val;
|
||||
kp->pressed_cnt++;
|
||||
assert_irq = 1;
|
||||
}
|
||||
}
|
||||
kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
|
||||
if (kp->pressed_cnt == 1) {
|
||||
kp->kpas &= ~((0xf << 4) | 0xf);
|
||||
if (rel) {
|
||||
pxa27x_keypad_find_pressed_key(kp, &row, &col);
|
||||
}
|
||||
kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
|
||||
}
|
||||
|
||||
if (!(kp->kpc & (KPC_AS | KPC_ASACT)))
|
||||
assert_irq = 0;
|
||||
|
||||
if (assert_irq && (kp->kpc & KPC_MIE)) {
|
||||
kp->kpc |= KPC_MI;
|
||||
qemu_irq_raise(kp->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
|
||||
uint32_t tmp;
|
||||
|
||||
switch (offset) {
|
||||
case KPC:
|
||||
tmp = s->kpc;
|
||||
if(tmp & KPC_MI)
|
||||
s->kpc &= ~(KPC_MI);
|
||||
if(tmp & KPC_DI)
|
||||
s->kpc &= ~(KPC_DI);
|
||||
qemu_irq_lower(s->irq);
|
||||
return tmp;
|
||||
case KPDK:
|
||||
return s->kpdk;
|
||||
case KPREC:
|
||||
tmp = s->kprec;
|
||||
if(tmp & KPREC_OF1)
|
||||
s->kprec &= ~(KPREC_OF1);
|
||||
if(tmp & KPREC_UF1)
|
||||
s->kprec &= ~(KPREC_UF1);
|
||||
if(tmp & KPREC_OF0)
|
||||
s->kprec &= ~(KPREC_OF0);
|
||||
if(tmp & KPREC_UF0)
|
||||
s->kprec &= ~(KPREC_UF0);
|
||||
return tmp;
|
||||
case KPMK:
|
||||
tmp = s->kpmk;
|
||||
if(tmp & KPMK_MKP)
|
||||
s->kpmk &= ~(KPMK_MKP);
|
||||
return tmp;
|
||||
case KPAS:
|
||||
return s->kpas;
|
||||
case KPASMKP0:
|
||||
return s->kpasmkp[0];
|
||||
case KPASMKP1:
|
||||
return s->kpasmkp[1];
|
||||
case KPASMKP2:
|
||||
return s->kpasmkp[2];
|
||||
case KPASMKP3:
|
||||
return s->kpasmkp[3];
|
||||
case KPKDI:
|
||||
return s->kpkdi;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad read offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
|
||||
|
||||
switch (offset) {
|
||||
case KPC:
|
||||
s->kpc = value;
|
||||
if (s->kpc & KPC_AS) {
|
||||
s->kpc &= ~(KPC_AS);
|
||||
}
|
||||
break;
|
||||
case KPDK:
|
||||
s->kpdk = value;
|
||||
break;
|
||||
case KPREC:
|
||||
s->kprec = value;
|
||||
break;
|
||||
case KPMK:
|
||||
s->kpmk = value;
|
||||
break;
|
||||
case KPAS:
|
||||
s->kpas = value;
|
||||
break;
|
||||
case KPASMKP0:
|
||||
s->kpasmkp[0] = value;
|
||||
break;
|
||||
case KPASMKP1:
|
||||
s->kpasmkp[1] = value;
|
||||
break;
|
||||
case KPASMKP2:
|
||||
s->kpasmkp[2] = value;
|
||||
break;
|
||||
case KPASMKP3:
|
||||
s->kpasmkp[3] = value;
|
||||
break;
|
||||
case KPKDI:
|
||||
s->kpkdi = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad write offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pxa2xx_keypad_ops = {
|
||||
.read = pxa2xx_keypad_read,
|
||||
.write = pxa2xx_keypad_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_pxa2xx_keypad = {
|
||||
.name = "pxa2xx_keypad",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
|
||||
VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
|
||||
VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
|
||||
VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
|
||||
VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
|
||||
VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
|
||||
VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
|
||||
hwaddr base,
|
||||
qemu_irq irq)
|
||||
{
|
||||
PXA2xxKeyPadState *s;
|
||||
|
||||
s = g_new0(PXA2xxKeyPadState, 1);
|
||||
s->irq = irq;
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &pxa2xx_keypad_ops, s,
|
||||
"pxa2xx-keypad", 0x00100000);
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
|
||||
vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void pxa27x_register_keypad(PXA2xxKeyPadState *kp,
|
||||
const struct keymap *map, int size)
|
||||
{
|
||||
if(!map || size < 0x80) {
|
||||
fprintf(stderr, "%s - No PXA keypad map defined\n", __func__);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
kp->map = map;
|
||||
qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
|
||||
}
|
|
@ -46,9 +46,6 @@ ps2_mouse_reset(void *opaque) "%p"
|
|||
hid_kbd_queue_full(void) "queue full"
|
||||
hid_kbd_queue_empty(void) "queue empty"
|
||||
|
||||
# tsc2005.c
|
||||
tsc2005_sense(const char *state) "touchscreen sense %s"
|
||||
|
||||
# virtio-input.c
|
||||
virtio_input_queue_full(void) "queue full"
|
||||
|
||||
|
|
|
@ -1,571 +0,0 @@
|
|||
/*
|
||||
* TI TSC2005 emulator.
|
||||
*
|
||||
* Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/input/tsc2xxx.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10)))
|
||||
|
||||
typedef struct {
|
||||
qemu_irq pint; /* Combination of the nPENIRQ and DAV signals */
|
||||
QEMUTimer *timer;
|
||||
uint16_t model;
|
||||
|
||||
int32_t x, y;
|
||||
bool pressure;
|
||||
|
||||
uint8_t reg, state;
|
||||
bool irq, command;
|
||||
uint16_t data, dav;
|
||||
|
||||
bool busy;
|
||||
bool enabled;
|
||||
bool host_mode;
|
||||
int8_t function;
|
||||
int8_t nextfunction;
|
||||
bool precision;
|
||||
bool nextprecision;
|
||||
uint16_t filter;
|
||||
uint8_t pin_func;
|
||||
uint16_t timing[2];
|
||||
uint8_t noise;
|
||||
bool reset;
|
||||
bool pdst;
|
||||
bool pnd0;
|
||||
uint16_t temp_thr[2];
|
||||
uint16_t aux_thr[2];
|
||||
|
||||
int32_t tr[8];
|
||||
} TSC2005State;
|
||||
|
||||
enum {
|
||||
TSC_MODE_XYZ_SCAN = 0x0,
|
||||
TSC_MODE_XY_SCAN,
|
||||
TSC_MODE_X,
|
||||
TSC_MODE_Y,
|
||||
TSC_MODE_Z,
|
||||
TSC_MODE_AUX,
|
||||
TSC_MODE_TEMP1,
|
||||
TSC_MODE_TEMP2,
|
||||
TSC_MODE_AUX_SCAN,
|
||||
TSC_MODE_X_TEST,
|
||||
TSC_MODE_Y_TEST,
|
||||
TSC_MODE_TS_TEST,
|
||||
TSC_MODE_RESERVED,
|
||||
TSC_MODE_XX_DRV,
|
||||
TSC_MODE_YY_DRV,
|
||||
TSC_MODE_YX_DRV,
|
||||
};
|
||||
|
||||
static const uint16_t mode_regs[16] = {
|
||||
0xf000, /* X, Y, Z scan */
|
||||
0xc000, /* X, Y scan */
|
||||
0x8000, /* X */
|
||||
0x4000, /* Y */
|
||||
0x3000, /* Z */
|
||||
0x0800, /* AUX */
|
||||
0x0400, /* TEMP1 */
|
||||
0x0200, /* TEMP2 */
|
||||
0x0800, /* AUX scan */
|
||||
0x0040, /* X test */
|
||||
0x0020, /* Y test */
|
||||
0x0080, /* Short-circuit test */
|
||||
0x0000, /* Reserved */
|
||||
0x0000, /* X+, X- drivers */
|
||||
0x0000, /* Y+, Y- drivers */
|
||||
0x0000, /* Y+, X- drivers */
|
||||
};
|
||||
|
||||
#define X_TRANSFORM(s) \
|
||||
((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
|
||||
#define Y_TRANSFORM(s) \
|
||||
((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
|
||||
#define Z1_TRANSFORM(s) \
|
||||
((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
|
||||
#define Z2_TRANSFORM(s) \
|
||||
((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
|
||||
|
||||
#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */
|
||||
#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */
|
||||
#define TEMP2_VAL (1531 << 4) /* +/- 5 at 12-bit */
|
||||
|
||||
static uint16_t tsc2005_read(TSC2005State *s, int reg)
|
||||
{
|
||||
uint16_t ret;
|
||||
|
||||
switch (reg) {
|
||||
case 0x0: /* X */
|
||||
s->dav &= ~mode_regs[TSC_MODE_X];
|
||||
return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
|
||||
(s->noise & 3);
|
||||
case 0x1: /* Y */
|
||||
s->dav &= ~mode_regs[TSC_MODE_Y];
|
||||
s->noise++;
|
||||
return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
|
||||
(s->noise & 3);
|
||||
case 0x2: /* Z1 */
|
||||
s->dav &= 0xdfff;
|
||||
return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
|
||||
(s->noise & 3);
|
||||
case 0x3: /* Z2 */
|
||||
s->dav &= 0xefff;
|
||||
return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
|
||||
(s->noise & 3);
|
||||
|
||||
case 0x4: /* AUX */
|
||||
s->dav &= ~mode_regs[TSC_MODE_AUX];
|
||||
return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
|
||||
|
||||
case 0x5: /* TEMP1 */
|
||||
s->dav &= ~mode_regs[TSC_MODE_TEMP1];
|
||||
return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
|
||||
(s->noise & 5);
|
||||
case 0x6: /* TEMP2 */
|
||||
s->dav &= 0xdfff;
|
||||
s->dav &= ~mode_regs[TSC_MODE_TEMP2];
|
||||
return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
|
||||
(s->noise & 3);
|
||||
|
||||
case 0x7: /* Status */
|
||||
ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
|
||||
s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
|
||||
mode_regs[TSC_MODE_TS_TEST]);
|
||||
s->reset = true;
|
||||
return ret;
|
||||
|
||||
case 0x8: /* AUX high threshold */
|
||||
return s->aux_thr[1];
|
||||
case 0x9: /* AUX low threshold */
|
||||
return s->aux_thr[0];
|
||||
|
||||
case 0xa: /* TEMP high threshold */
|
||||
return s->temp_thr[1];
|
||||
case 0xb: /* TEMP low threshold */
|
||||
return s->temp_thr[0];
|
||||
|
||||
case 0xc: /* CFR0 */
|
||||
return (s->pressure << 15) | ((!s->busy) << 14) |
|
||||
(s->nextprecision << 13) | s->timing[0];
|
||||
case 0xd: /* CFR1 */
|
||||
return s->timing[1];
|
||||
case 0xe: /* CFR2 */
|
||||
return (s->pin_func << 14) | s->filter;
|
||||
|
||||
case 0xf: /* Function select status */
|
||||
return s->function >= 0 ? 1 << s->function : 0;
|
||||
}
|
||||
|
||||
/* Never gets here */
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
|
||||
{
|
||||
switch (reg) {
|
||||
case 0x8: /* AUX high threshold */
|
||||
s->aux_thr[1] = data;
|
||||
break;
|
||||
case 0x9: /* AUX low threshold */
|
||||
s->aux_thr[0] = data;
|
||||
break;
|
||||
|
||||
case 0xa: /* TEMP high threshold */
|
||||
s->temp_thr[1] = data;
|
||||
break;
|
||||
case 0xb: /* TEMP low threshold */
|
||||
s->temp_thr[0] = data;
|
||||
break;
|
||||
|
||||
case 0xc: /* CFR0 */
|
||||
s->host_mode = (data >> 15) != 0;
|
||||
if (s->enabled != !(data & 0x4000)) {
|
||||
s->enabled = !(data & 0x4000);
|
||||
trace_tsc2005_sense(s->enabled ? "enabled" : "disabled");
|
||||
if (s->busy && !s->enabled) {
|
||||
timer_del(s->timer);
|
||||
}
|
||||
s->busy = s->busy && s->enabled;
|
||||
}
|
||||
s->nextprecision = (data >> 13) & 1;
|
||||
s->timing[0] = data & 0x1fff;
|
||||
if ((s->timing[0] >> 11) == 3) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"tsc2005_write: illegal conversion clock setting\n");
|
||||
}
|
||||
break;
|
||||
case 0xd: /* CFR1 */
|
||||
s->timing[1] = data & 0xf07;
|
||||
break;
|
||||
case 0xe: /* CFR2 */
|
||||
s->pin_func = (data >> 14) & 3;
|
||||
s->filter = data & 0x3fff;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: write into read-only register 0x%x\n",
|
||||
__func__, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/* This handles most of the chip's logic. */
|
||||
static void tsc2005_pin_update(TSC2005State *s)
|
||||
{
|
||||
int64_t expires;
|
||||
bool pin_state;
|
||||
|
||||
switch (s->pin_func) {
|
||||
case 0:
|
||||
pin_state = !s->pressure && !!s->dav;
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
default:
|
||||
pin_state = !s->dav;
|
||||
break;
|
||||
case 2:
|
||||
pin_state = !s->pressure;
|
||||
}
|
||||
|
||||
if (pin_state != s->irq) {
|
||||
s->irq = pin_state;
|
||||
qemu_set_irq(s->pint, s->irq);
|
||||
}
|
||||
|
||||
switch (s->nextfunction) {
|
||||
case TSC_MODE_XYZ_SCAN:
|
||||
case TSC_MODE_XY_SCAN:
|
||||
if (!s->host_mode && s->dav) {
|
||||
s->enabled = false;
|
||||
}
|
||||
if (!s->pressure) {
|
||||
return;
|
||||
}
|
||||
/* Fall through */
|
||||
case TSC_MODE_AUX_SCAN:
|
||||
break;
|
||||
|
||||
case TSC_MODE_X:
|
||||
case TSC_MODE_Y:
|
||||
case TSC_MODE_Z:
|
||||
if (!s->pressure) {
|
||||
return;
|
||||
}
|
||||
/* Fall through */
|
||||
case TSC_MODE_AUX:
|
||||
case TSC_MODE_TEMP1:
|
||||
case TSC_MODE_TEMP2:
|
||||
case TSC_MODE_X_TEST:
|
||||
case TSC_MODE_Y_TEST:
|
||||
case TSC_MODE_TS_TEST:
|
||||
if (s->dav) {
|
||||
s->enabled = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case TSC_MODE_RESERVED:
|
||||
case TSC_MODE_XX_DRV:
|
||||
case TSC_MODE_YY_DRV:
|
||||
case TSC_MODE_YX_DRV:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->enabled || s->busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->busy = true;
|
||||
s->precision = s->nextprecision;
|
||||
s->function = s->nextfunction;
|
||||
s->pdst = !s->pnd0; /* Synchronised on internal clock */
|
||||
expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
(NANOSECONDS_PER_SECOND >> 7);
|
||||
timer_mod(s->timer, expires);
|
||||
}
|
||||
|
||||
static void tsc2005_reset(TSC2005State *s)
|
||||
{
|
||||
s->state = 0;
|
||||
s->pin_func = 0;
|
||||
s->enabled = false;
|
||||
s->busy = false;
|
||||
s->nextprecision = false;
|
||||
s->nextfunction = 0;
|
||||
s->timing[0] = 0;
|
||||
s->timing[1] = 0;
|
||||
s->irq = false;
|
||||
s->dav = 0;
|
||||
s->reset = false;
|
||||
s->pdst = true;
|
||||
s->pnd0 = false;
|
||||
s->function = -1;
|
||||
s->temp_thr[0] = 0x000;
|
||||
s->temp_thr[1] = 0xfff;
|
||||
s->aux_thr[0] = 0x000;
|
||||
s->aux_thr[1] = 0xfff;
|
||||
|
||||
tsc2005_pin_update(s);
|
||||
}
|
||||
|
||||
static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
|
||||
{
|
||||
TSC2005State *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (s->state++) {
|
||||
case 0:
|
||||
if (value & 0x80) {
|
||||
/* Command */
|
||||
if (value & (1 << 1))
|
||||
tsc2005_reset(s);
|
||||
else {
|
||||
s->nextfunction = (value >> 3) & 0xf;
|
||||
s->nextprecision = (value >> 2) & 1;
|
||||
if (s->enabled != !(value & 1)) {
|
||||
s->enabled = !(value & 1);
|
||||
trace_tsc2005_sense(s->enabled ? "enabled" : "disabled");
|
||||
if (s->busy && !s->enabled) {
|
||||
timer_del(s->timer);
|
||||
}
|
||||
s->busy = s->busy && s->enabled;
|
||||
}
|
||||
tsc2005_pin_update(s);
|
||||
}
|
||||
|
||||
s->state = 0;
|
||||
} else if (value) {
|
||||
/* Data transfer */
|
||||
s->reg = (value >> 3) & 0xf;
|
||||
s->pnd0 = (value >> 1) & 1;
|
||||
s->command = value & 1;
|
||||
|
||||
if (s->command) {
|
||||
/* Read */
|
||||
s->data = tsc2005_read(s, s->reg);
|
||||
tsc2005_pin_update(s);
|
||||
} else
|
||||
s->data = 0;
|
||||
} else
|
||||
s->state = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (s->command) {
|
||||
ret = (s->data >> 8) & 0xff;
|
||||
} else {
|
||||
s->data |= value << 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (s->command)
|
||||
ret = s->data & 0xff;
|
||||
else {
|
||||
s->data |= value;
|
||||
tsc2005_write(s, s->reg, s->data);
|
||||
tsc2005_pin_update(s);
|
||||
}
|
||||
|
||||
s->state = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
len &= ~7;
|
||||
while (len > 0) {
|
||||
len -= 8;
|
||||
ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tsc2005_timer_tick(void *opaque)
|
||||
{
|
||||
TSC2005State *s = opaque;
|
||||
unsigned int function = s->function;
|
||||
|
||||
assert(function < ARRAY_SIZE(mode_regs));
|
||||
|
||||
/* Timer ticked -- a set of conversions has been finished. */
|
||||
|
||||
if (!s->busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->busy = false;
|
||||
s->dav |= mode_regs[function];
|
||||
s->function = -1;
|
||||
tsc2005_pin_update(s);
|
||||
}
|
||||
|
||||
static void tsc2005_touchscreen_event(void *opaque,
|
||||
int x, int y, int z, int buttons_state)
|
||||
{
|
||||
TSC2005State *s = opaque;
|
||||
int p = s->pressure;
|
||||
|
||||
if (buttons_state) {
|
||||
s->x = x;
|
||||
s->y = y;
|
||||
}
|
||||
s->pressure = !!buttons_state;
|
||||
|
||||
/*
|
||||
* Note: We would get better responsiveness in the guest by
|
||||
* signaling TS events immediately, but for now we simulate
|
||||
* the first conversion delay for sake of correctness.
|
||||
*/
|
||||
if (p != s->pressure) {
|
||||
tsc2005_pin_update(s);
|
||||
}
|
||||
}
|
||||
|
||||
static int tsc2005_post_load(void *opaque, int version_id)
|
||||
{
|
||||
TSC2005State *s = (TSC2005State *) opaque;
|
||||
|
||||
s->busy = timer_pending(s->timer);
|
||||
tsc2005_pin_update(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_tsc2005 = {
|
||||
.name = "tsc2005",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.post_load = tsc2005_post_load,
|
||||
.fields = (const VMStateField []) {
|
||||
VMSTATE_BOOL(pressure, TSC2005State),
|
||||
VMSTATE_BOOL(irq, TSC2005State),
|
||||
VMSTATE_BOOL(command, TSC2005State),
|
||||
VMSTATE_BOOL(enabled, TSC2005State),
|
||||
VMSTATE_BOOL(host_mode, TSC2005State),
|
||||
VMSTATE_BOOL(reset, TSC2005State),
|
||||
VMSTATE_BOOL(pdst, TSC2005State),
|
||||
VMSTATE_BOOL(pnd0, TSC2005State),
|
||||
VMSTATE_BOOL(precision, TSC2005State),
|
||||
VMSTATE_BOOL(nextprecision, TSC2005State),
|
||||
VMSTATE_UINT8(reg, TSC2005State),
|
||||
VMSTATE_UINT8(state, TSC2005State),
|
||||
VMSTATE_UINT16(data, TSC2005State),
|
||||
VMSTATE_UINT16(dav, TSC2005State),
|
||||
VMSTATE_UINT16(filter, TSC2005State),
|
||||
VMSTATE_INT8(nextfunction, TSC2005State),
|
||||
VMSTATE_INT8(function, TSC2005State),
|
||||
VMSTATE_INT32(x, TSC2005State),
|
||||
VMSTATE_INT32(y, TSC2005State),
|
||||
VMSTATE_TIMER_PTR(timer, TSC2005State),
|
||||
VMSTATE_UINT8(pin_func, TSC2005State),
|
||||
VMSTATE_UINT16_ARRAY(timing, TSC2005State, 2),
|
||||
VMSTATE_UINT8(noise, TSC2005State),
|
||||
VMSTATE_UINT16_ARRAY(temp_thr, TSC2005State, 2),
|
||||
VMSTATE_UINT16_ARRAY(aux_thr, TSC2005State, 2),
|
||||
VMSTATE_INT32_ARRAY(tr, TSC2005State, 8),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
void *tsc2005_init(qemu_irq pintdav)
|
||||
{
|
||||
TSC2005State *s;
|
||||
|
||||
s = g_new0(TSC2005State, 1);
|
||||
s->x = 400;
|
||||
s->y = 240;
|
||||
s->pressure = false;
|
||||
s->precision = s->nextprecision = false;
|
||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s);
|
||||
s->pint = pintdav;
|
||||
s->model = 0x2005;
|
||||
|
||||
s->tr[0] = 0;
|
||||
s->tr[1] = 1;
|
||||
s->tr[2] = 1;
|
||||
s->tr[3] = 0;
|
||||
s->tr[4] = 1;
|
||||
s->tr[5] = 0;
|
||||
s->tr[6] = 1;
|
||||
s->tr[7] = 0;
|
||||
|
||||
tsc2005_reset(s);
|
||||
|
||||
qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1,
|
||||
"QEMU TSC2005-driven Touchscreen");
|
||||
|
||||
qemu_register_reset((void *) tsc2005_reset, s);
|
||||
vmstate_register(NULL, 0, &vmstate_tsc2005, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use tslib generated calibration data to generate ADC input values
|
||||
* from the touchscreen. Assuming 12-bit precision was used during
|
||||
* tslib calibration.
|
||||
*/
|
||||
void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info)
|
||||
{
|
||||
TSC2005State *s = (TSC2005State *) opaque;
|
||||
|
||||
/* This version assumes touchscreen X & Y axis are parallel or
|
||||
* perpendicular to LCD's X & Y axis in some way. */
|
||||
if (abs(info->a[0]) > abs(info->a[1])) {
|
||||
s->tr[0] = 0;
|
||||
s->tr[1] = -info->a[6] * info->x;
|
||||
s->tr[2] = info->a[0];
|
||||
s->tr[3] = -info->a[2] / info->a[0];
|
||||
s->tr[4] = info->a[6] * info->y;
|
||||
s->tr[5] = 0;
|
||||
s->tr[6] = info->a[4];
|
||||
s->tr[7] = -info->a[5] / info->a[4];
|
||||
} else {
|
||||
s->tr[0] = info->a[6] * info->y;
|
||||
s->tr[1] = 0;
|
||||
s->tr[2] = info->a[1];
|
||||
s->tr[3] = -info->a[2] / info->a[1];
|
||||
s->tr[4] = 0;
|
||||
s->tr[5] = -info->a[6] * info->x;
|
||||
s->tr[6] = info->a[3];
|
||||
s->tr[7] = -info->a[5] / info->a[3];
|
||||
}
|
||||
|
||||
s->tr[0] >>= 11;
|
||||
s->tr[1] >>= 11;
|
||||
s->tr[3] <<= 4;
|
||||
s->tr[4] >>= 11;
|
||||
s->tr[5] >>= 11;
|
||||
s->tr[7] <<= 4;
|
||||
}
|
1241
hw/input/tsc210x.c
1241
hw/input/tsc210x.c
File diff suppressed because it is too large
Load Diff
|
@ -50,8 +50,6 @@ struct OMAPIntcState {
|
|||
int level_only;
|
||||
uint32_t size;
|
||||
|
||||
uint8_t revision;
|
||||
|
||||
/* state */
|
||||
uint32_t new_agr[2];
|
||||
int sir_intr[2];
|
||||
|
@ -133,26 +131,6 @@ static void omap_set_intr(void *opaque, int irq, int req)
|
|||
}
|
||||
}
|
||||
|
||||
/* Simplified version with no edge detection */
|
||||
static void omap_set_intr_noedge(void *opaque, int irq, int req)
|
||||
{
|
||||
OMAPIntcState *ih = opaque;
|
||||
uint32_t rise;
|
||||
|
||||
struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
|
||||
int n = irq & 31;
|
||||
|
||||
if (req) {
|
||||
rise = ~bank->inputs & (1 << n);
|
||||
if (rise) {
|
||||
bank->irqs |= bank->inputs |= rise;
|
||||
omap_inth_update(ih, 0);
|
||||
omap_inth_update(ih, 1);
|
||||
}
|
||||
} else
|
||||
bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
|
||||
}
|
||||
|
||||
static uint64_t omap_inth_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
|
@ -420,259 +398,6 @@ static const TypeInfo omap_intc_info = {
|
|||
.class_init = omap_intc_class_init,
|
||||
};
|
||||
|
||||
static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
OMAPIntcState *s = opaque;
|
||||
int offset = addr;
|
||||
int bank_no, line_no;
|
||||
struct omap_intr_handler_bank_s *bank = NULL;
|
||||
|
||||
if ((offset & 0xf80) == 0x80) {
|
||||
bank_no = (offset & 0x60) >> 5;
|
||||
if (bank_no < s->nbanks) {
|
||||
offset &= ~0x60;
|
||||
bank = &s->bank[bank_no];
|
||||
} else {
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case 0x00: /* INTC_REVISION */
|
||||
return s->revision;
|
||||
|
||||
case 0x10: /* INTC_SYSCONFIG */
|
||||
return (s->autoidle >> 2) & 1;
|
||||
|
||||
case 0x14: /* INTC_SYSSTATUS */
|
||||
return 1; /* RESETDONE */
|
||||
|
||||
case 0x40: /* INTC_SIR_IRQ */
|
||||
return s->sir_intr[0];
|
||||
|
||||
case 0x44: /* INTC_SIR_FIQ */
|
||||
return s->sir_intr[1];
|
||||
|
||||
case 0x48: /* INTC_CONTROL */
|
||||
return (!s->mask) << 2; /* GLOBALMASK */
|
||||
|
||||
case 0x4c: /* INTC_PROTECTION */
|
||||
return 0;
|
||||
|
||||
case 0x50: /* INTC_IDLE */
|
||||
return s->autoidle & 3;
|
||||
|
||||
/* Per-bank registers */
|
||||
case 0x80: /* INTC_ITR */
|
||||
return bank->inputs;
|
||||
|
||||
case 0x84: /* INTC_MIR */
|
||||
return bank->mask;
|
||||
|
||||
case 0x88: /* INTC_MIR_CLEAR */
|
||||
case 0x8c: /* INTC_MIR_SET */
|
||||
return 0;
|
||||
|
||||
case 0x90: /* INTC_ISR_SET */
|
||||
return bank->swi;
|
||||
|
||||
case 0x94: /* INTC_ISR_CLEAR */
|
||||
return 0;
|
||||
|
||||
case 0x98: /* INTC_PENDING_IRQ */
|
||||
return bank->irqs & ~bank->mask & ~bank->fiq;
|
||||
|
||||
case 0x9c: /* INTC_PENDING_FIQ */
|
||||
return bank->irqs & ~bank->mask & bank->fiq;
|
||||
|
||||
/* Per-line registers */
|
||||
case 0x100 ... 0x300: /* INTC_ILR */
|
||||
bank_no = (offset - 0x100) >> 7;
|
||||
if (bank_no > s->nbanks)
|
||||
break;
|
||||
bank = &s->bank[bank_no];
|
||||
line_no = (offset & 0x7f) >> 2;
|
||||
return (bank->priority[line_no] << 2) |
|
||||
((bank->fiq >> line_no) & 1);
|
||||
}
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap2_inth_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
OMAPIntcState *s = opaque;
|
||||
int offset = addr;
|
||||
int bank_no, line_no;
|
||||
struct omap_intr_handler_bank_s *bank = NULL;
|
||||
|
||||
if ((offset & 0xf80) == 0x80) {
|
||||
bank_no = (offset & 0x60) >> 5;
|
||||
if (bank_no < s->nbanks) {
|
||||
offset &= ~0x60;
|
||||
bank = &s->bank[bank_no];
|
||||
} else {
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case 0x10: /* INTC_SYSCONFIG */
|
||||
s->autoidle &= 4;
|
||||
s->autoidle |= (value & 1) << 2;
|
||||
if (value & 2) { /* SOFTRESET */
|
||||
omap_inth_reset(DEVICE(s));
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x48: /* INTC_CONTROL */
|
||||
s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */
|
||||
if (value & 2) { /* NEWFIQAGR */
|
||||
qemu_set_irq(s->parent_intr[1], 0);
|
||||
s->new_agr[1] = ~0;
|
||||
omap_inth_update(s, 1);
|
||||
}
|
||||
if (value & 1) { /* NEWIRQAGR */
|
||||
qemu_set_irq(s->parent_intr[0], 0);
|
||||
s->new_agr[0] = ~0;
|
||||
omap_inth_update(s, 0);
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x4c: /* INTC_PROTECTION */
|
||||
/* TODO: Make a bitmap (or sizeof(char)map) of access privileges
|
||||
* for every register, see Chapter 3 and 4 for privileged mode. */
|
||||
if (value & 1)
|
||||
fprintf(stderr, "%s: protection mode enable attempt\n",
|
||||
__func__);
|
||||
return;
|
||||
|
||||
case 0x50: /* INTC_IDLE */
|
||||
s->autoidle &= ~3;
|
||||
s->autoidle |= value & 3;
|
||||
return;
|
||||
|
||||
/* Per-bank registers */
|
||||
case 0x84: /* INTC_MIR */
|
||||
bank->mask = value;
|
||||
omap_inth_update(s, 0);
|
||||
omap_inth_update(s, 1);
|
||||
return;
|
||||
|
||||
case 0x88: /* INTC_MIR_CLEAR */
|
||||
bank->mask &= ~value;
|
||||
omap_inth_update(s, 0);
|
||||
omap_inth_update(s, 1);
|
||||
return;
|
||||
|
||||
case 0x8c: /* INTC_MIR_SET */
|
||||
bank->mask |= value;
|
||||
return;
|
||||
|
||||
case 0x90: /* INTC_ISR_SET */
|
||||
bank->irqs |= bank->swi |= value;
|
||||
omap_inth_update(s, 0);
|
||||
omap_inth_update(s, 1);
|
||||
return;
|
||||
|
||||
case 0x94: /* INTC_ISR_CLEAR */
|
||||
bank->swi &= ~value;
|
||||
bank->irqs = bank->swi & bank->inputs;
|
||||
return;
|
||||
|
||||
/* Per-line registers */
|
||||
case 0x100 ... 0x300: /* INTC_ILR */
|
||||
bank_no = (offset - 0x100) >> 7;
|
||||
if (bank_no > s->nbanks)
|
||||
break;
|
||||
bank = &s->bank[bank_no];
|
||||
line_no = (offset & 0x7f) >> 2;
|
||||
bank->priority[line_no] = (value >> 2) & 0x3f;
|
||||
bank->fiq &= ~(1 << line_no);
|
||||
bank->fiq |= (value & 1) << line_no;
|
||||
return;
|
||||
|
||||
case 0x00: /* INTC_REVISION */
|
||||
case 0x14: /* INTC_SYSSTATUS */
|
||||
case 0x40: /* INTC_SIR_IRQ */
|
||||
case 0x44: /* INTC_SIR_FIQ */
|
||||
case 0x80: /* INTC_ITR */
|
||||
case 0x98: /* INTC_PENDING_IRQ */
|
||||
case 0x9c: /* INTC_PENDING_FIQ */
|
||||
OMAP_RO_REG(addr);
|
||||
return;
|
||||
}
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap2_inth_mem_ops = {
|
||||
.read = omap2_inth_read,
|
||||
.write = omap2_inth_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void omap2_intc_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
OMAPIntcState *s = OMAP_INTC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
s->level_only = 1;
|
||||
s->nbanks = 3;
|
||||
sysbus_init_irq(sbd, &s->parent_intr[0]);
|
||||
sysbus_init_irq(sbd, &s->parent_intr[1]);
|
||||
qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
|
||||
memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s,
|
||||
"omap2-intc", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
}
|
||||
|
||||
static void omap2_intc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
OMAPIntcState *s = OMAP_INTC(dev);
|
||||
|
||||
if (!s->iclk) {
|
||||
error_setg(errp, "omap2-intc: iclk not connected");
|
||||
return;
|
||||
}
|
||||
if (!s->fclk) {
|
||||
error_setg(errp, "omap2-intc: fclk not connected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static Property omap2_intc_properties[] = {
|
||||
DEFINE_PROP_UINT8("revision", OMAPIntcState,
|
||||
revision, 0x21),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void omap2_intc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
device_class_set_legacy_reset(dc, omap_inth_reset);
|
||||
device_class_set_props(dc, omap2_intc_properties);
|
||||
/* Reason: pointer property "iclk", "fclk" */
|
||||
dc->user_creatable = false;
|
||||
dc->realize = omap2_intc_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo omap2_intc_info = {
|
||||
.name = "omap2-intc",
|
||||
.parent = TYPE_OMAP_INTC,
|
||||
.instance_init = omap2_intc_init,
|
||||
.class_init = omap2_intc_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo omap_intc_type_info = {
|
||||
.name = TYPE_OMAP_INTC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
|
@ -684,7 +409,6 @@ static void omap_intc_register_types(void)
|
|||
{
|
||||
type_register_static(&omap_intc_type_info);
|
||||
type_register_static(&omap_intc_info);
|
||||
type_register_static(&omap2_intc_info);
|
||||
}
|
||||
|
||||
type_init(omap_intc_register_types)
|
||||
|
|
619
hw/misc/cbus.c
619
hw/misc/cbus.c
|
@ -1,619 +0,0 @@
|
|||
/*
|
||||
* CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
|
||||
* Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
|
||||
* Based on reverse-engineering of a linux driver.
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/misc/cbus.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
typedef struct {
|
||||
void *opaque;
|
||||
void (*io)(void *opaque, int rw, int reg, uint16_t *val);
|
||||
int addr;
|
||||
} CBusSlave;
|
||||
|
||||
typedef struct {
|
||||
CBus cbus;
|
||||
|
||||
int sel;
|
||||
int dat;
|
||||
int clk;
|
||||
int bit;
|
||||
int dir;
|
||||
uint16_t val;
|
||||
qemu_irq dat_out;
|
||||
|
||||
int addr;
|
||||
int reg;
|
||||
int rw;
|
||||
enum {
|
||||
cbus_address,
|
||||
cbus_value,
|
||||
} cycle;
|
||||
|
||||
CBusSlave *slave[8];
|
||||
} CBusPriv;
|
||||
|
||||
static void cbus_io(CBusPriv *s)
|
||||
{
|
||||
if (s->slave[s->addr])
|
||||
s->slave[s->addr]->io(s->slave[s->addr]->opaque,
|
||||
s->rw, s->reg, &s->val);
|
||||
else
|
||||
hw_error("%s: bad slave address %i\n", __func__, s->addr);
|
||||
}
|
||||
|
||||
static void cbus_cycle(CBusPriv *s)
|
||||
{
|
||||
switch (s->cycle) {
|
||||
case cbus_address:
|
||||
s->addr = (s->val >> 6) & 7;
|
||||
s->rw = (s->val >> 5) & 1;
|
||||
s->reg = (s->val >> 0) & 0x1f;
|
||||
|
||||
s->cycle = cbus_value;
|
||||
s->bit = 15;
|
||||
s->dir = !s->rw;
|
||||
s->val = 0;
|
||||
|
||||
if (s->rw)
|
||||
cbus_io(s);
|
||||
break;
|
||||
|
||||
case cbus_value:
|
||||
if (!s->rw)
|
||||
cbus_io(s);
|
||||
|
||||
s->cycle = cbus_address;
|
||||
s->bit = 8;
|
||||
s->dir = 1;
|
||||
s->val = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cbus_clk(void *opaque, int line, int level)
|
||||
{
|
||||
CBusPriv *s = (CBusPriv *) opaque;
|
||||
|
||||
if (!s->sel && level && !s->clk) {
|
||||
if (s->dir)
|
||||
s->val |= s->dat << (s->bit --);
|
||||
else
|
||||
qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
|
||||
|
||||
if (s->bit < 0)
|
||||
cbus_cycle(s);
|
||||
}
|
||||
|
||||
s->clk = level;
|
||||
}
|
||||
|
||||
static void cbus_dat(void *opaque, int line, int level)
|
||||
{
|
||||
CBusPriv *s = (CBusPriv *) opaque;
|
||||
|
||||
s->dat = level;
|
||||
}
|
||||
|
||||
static void cbus_sel(void *opaque, int line, int level)
|
||||
{
|
||||
CBusPriv *s = (CBusPriv *) opaque;
|
||||
|
||||
if (!level) {
|
||||
s->dir = 1;
|
||||
s->bit = 8;
|
||||
s->val = 0;
|
||||
}
|
||||
|
||||
s->sel = level;
|
||||
}
|
||||
|
||||
CBus *cbus_init(qemu_irq dat)
|
||||
{
|
||||
CBusPriv *s = g_malloc0(sizeof(*s));
|
||||
|
||||
s->dat_out = dat;
|
||||
s->cbus.clk = qemu_allocate_irq(cbus_clk, s, 0);
|
||||
s->cbus.dat = qemu_allocate_irq(cbus_dat, s, 0);
|
||||
s->cbus.sel = qemu_allocate_irq(cbus_sel, s, 0);
|
||||
|
||||
s->sel = 1;
|
||||
s->clk = 0;
|
||||
s->dat = 0;
|
||||
|
||||
return &s->cbus;
|
||||
}
|
||||
|
||||
void cbus_attach(CBus *bus, void *slave_opaque)
|
||||
{
|
||||
CBusSlave *slave = (CBusSlave *) slave_opaque;
|
||||
CBusPriv *s = (CBusPriv *) bus;
|
||||
|
||||
s->slave[slave->addr] = slave;
|
||||
}
|
||||
|
||||
/* Retu/Vilma */
|
||||
typedef struct {
|
||||
uint16_t irqst;
|
||||
uint16_t irqen;
|
||||
uint16_t cc[2];
|
||||
int channel;
|
||||
uint16_t result[16];
|
||||
uint16_t sample;
|
||||
uint16_t status;
|
||||
|
||||
struct {
|
||||
uint16_t cal;
|
||||
} rtc;
|
||||
|
||||
int is_vilma;
|
||||
qemu_irq irq;
|
||||
CBusSlave cbus;
|
||||
} CBusRetu;
|
||||
|
||||
static void retu_interrupt_update(CBusRetu *s)
|
||||
{
|
||||
qemu_set_irq(s->irq, s->irqst & ~s->irqen);
|
||||
}
|
||||
|
||||
#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
|
||||
#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */
|
||||
#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */
|
||||
#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */
|
||||
#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */
|
||||
#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */
|
||||
#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */
|
||||
#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */
|
||||
#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */
|
||||
#define RETU_REG_AFCR 0x0a /* (RW) AFC register */
|
||||
#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */
|
||||
#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/
|
||||
#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */
|
||||
#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */
|
||||
#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */
|
||||
#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */
|
||||
#define RETU_REG_TXCR 0x11 /* (RW) TxC register */
|
||||
#define RETU_REG_STATUS 0x16 /* (RO) Status register */
|
||||
#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */
|
||||
#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */
|
||||
#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */
|
||||
#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */
|
||||
#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */
|
||||
#define RETU_REG_SGR1 0x1c /* (RW) */
|
||||
#define RETU_REG_SCR1 0x1d /* (RW) */
|
||||
#define RETU_REG_SGR2 0x1e /* (RW) */
|
||||
#define RETU_REG_SCR2 0x1f /* (RW) */
|
||||
|
||||
/* Retu Interrupt sources */
|
||||
enum {
|
||||
retu_int_pwr = 0, /* Power button */
|
||||
retu_int_char = 1, /* Charger */
|
||||
retu_int_rtcs = 2, /* Seconds */
|
||||
retu_int_rtcm = 3, /* Minutes */
|
||||
retu_int_rtcd = 4, /* Days */
|
||||
retu_int_rtca = 5, /* Alarm */
|
||||
retu_int_hook = 6, /* Hook */
|
||||
retu_int_head = 7, /* Headset */
|
||||
retu_int_adcs = 8, /* ADC sample */
|
||||
};
|
||||
|
||||
/* Retu ADC channel wiring */
|
||||
enum {
|
||||
retu_adc_bsi = 1, /* BSI */
|
||||
retu_adc_batt_temp = 2, /* Battery temperature */
|
||||
retu_adc_chg_volt = 3, /* Charger voltage */
|
||||
retu_adc_head_det = 4, /* Headset detection */
|
||||
retu_adc_hook_det = 5, /* Hook detection */
|
||||
retu_adc_rf_gp = 6, /* RF GP */
|
||||
retu_adc_tx_det = 7, /* Wideband Tx detection */
|
||||
retu_adc_batt_volt = 8, /* Battery voltage */
|
||||
retu_adc_sens = 10, /* Light sensor */
|
||||
retu_adc_sens_temp = 11, /* Light sensor temperature */
|
||||
retu_adc_bbatt_volt = 12, /* Backup battery voltage */
|
||||
retu_adc_self_temp = 13, /* RETU temperature */
|
||||
};
|
||||
|
||||
static inline uint16_t retu_read(CBusRetu *s, int reg)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("RETU read at %02x\n", reg);
|
||||
#endif
|
||||
|
||||
switch (reg) {
|
||||
case RETU_REG_ASICR:
|
||||
return 0x0215 | (s->is_vilma << 7);
|
||||
|
||||
case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
|
||||
return s->irqst;
|
||||
|
||||
case RETU_REG_IMR:
|
||||
return s->irqen;
|
||||
|
||||
case RETU_REG_RTCDSR:
|
||||
case RETU_REG_RTCHMR:
|
||||
case RETU_REG_RTCHMAR:
|
||||
/* TODO */
|
||||
return 0x0000;
|
||||
|
||||
case RETU_REG_RTCCALR:
|
||||
return s->rtc.cal;
|
||||
|
||||
case RETU_REG_ADCR:
|
||||
return (s->channel << 10) | s->result[s->channel];
|
||||
case RETU_REG_ADCSCR:
|
||||
return s->sample;
|
||||
|
||||
case RETU_REG_AFCR:
|
||||
case RETU_REG_ANTIFR:
|
||||
case RETU_REG_CALIBR:
|
||||
/* TODO */
|
||||
return 0x0000;
|
||||
|
||||
case RETU_REG_CCR1:
|
||||
return s->cc[0];
|
||||
case RETU_REG_CCR2:
|
||||
return s->cc[1];
|
||||
|
||||
case RETU_REG_RCTRL_CLR:
|
||||
case RETU_REG_RCTRL_SET:
|
||||
case RETU_REG_TXCR:
|
||||
/* TODO */
|
||||
return 0x0000;
|
||||
|
||||
case RETU_REG_STATUS:
|
||||
return s->status;
|
||||
|
||||
case RETU_REG_WATCHDOG:
|
||||
case RETU_REG_AUDTXR:
|
||||
case RETU_REG_AUDPAR:
|
||||
case RETU_REG_AUDRXR1:
|
||||
case RETU_REG_AUDRXR2:
|
||||
case RETU_REG_SGR1:
|
||||
case RETU_REG_SCR1:
|
||||
case RETU_REG_SGR2:
|
||||
case RETU_REG_SCR2:
|
||||
/* TODO */
|
||||
return 0x0000;
|
||||
|
||||
default:
|
||||
hw_error("%s: bad register %02x\n", __func__, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("RETU write of %04x at %02x\n", val, reg);
|
||||
#endif
|
||||
|
||||
switch (reg) {
|
||||
case RETU_REG_IDR:
|
||||
s->irqst ^= val;
|
||||
retu_interrupt_update(s);
|
||||
break;
|
||||
|
||||
case RETU_REG_IMR:
|
||||
s->irqen = val;
|
||||
retu_interrupt_update(s);
|
||||
break;
|
||||
|
||||
case RETU_REG_RTCDSR:
|
||||
case RETU_REG_RTCHMAR:
|
||||
/* TODO */
|
||||
break;
|
||||
|
||||
case RETU_REG_RTCCALR:
|
||||
s->rtc.cal = val;
|
||||
break;
|
||||
|
||||
case RETU_REG_ADCR:
|
||||
s->channel = (val >> 10) & 0xf;
|
||||
s->irqst |= 1 << retu_int_adcs;
|
||||
retu_interrupt_update(s);
|
||||
break;
|
||||
case RETU_REG_ADCSCR:
|
||||
s->sample &= ~val;
|
||||
break;
|
||||
|
||||
case RETU_REG_AFCR:
|
||||
case RETU_REG_ANTIFR:
|
||||
case RETU_REG_CALIBR:
|
||||
|
||||
case RETU_REG_CCR1:
|
||||
s->cc[0] = val;
|
||||
break;
|
||||
case RETU_REG_CCR2:
|
||||
s->cc[1] = val;
|
||||
break;
|
||||
|
||||
case RETU_REG_RCTRL_CLR:
|
||||
case RETU_REG_RCTRL_SET:
|
||||
/* TODO */
|
||||
break;
|
||||
|
||||
case RETU_REG_WATCHDOG:
|
||||
if (val == 0 && (s->cc[0] & 2))
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
break;
|
||||
|
||||
case RETU_REG_TXCR:
|
||||
case RETU_REG_AUDTXR:
|
||||
case RETU_REG_AUDPAR:
|
||||
case RETU_REG_AUDRXR1:
|
||||
case RETU_REG_AUDRXR2:
|
||||
case RETU_REG_SGR1:
|
||||
case RETU_REG_SCR1:
|
||||
case RETU_REG_SGR2:
|
||||
case RETU_REG_SCR2:
|
||||
/* TODO */
|
||||
break;
|
||||
|
||||
default:
|
||||
hw_error("%s: bad register %02x\n", __func__, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
|
||||
{
|
||||
CBusRetu *s = (CBusRetu *) opaque;
|
||||
|
||||
if (rw)
|
||||
*val = retu_read(s, reg);
|
||||
else
|
||||
retu_write(s, reg, *val);
|
||||
}
|
||||
|
||||
void *retu_init(qemu_irq irq, int vilma)
|
||||
{
|
||||
CBusRetu *s = g_malloc0(sizeof(*s));
|
||||
|
||||
s->irq = irq;
|
||||
s->irqen = 0xffff;
|
||||
s->irqst = 0x0000;
|
||||
s->status = 0x0020;
|
||||
s->is_vilma = !!vilma;
|
||||
s->rtc.cal = 0x01;
|
||||
s->result[retu_adc_bsi] = 0x3c2;
|
||||
s->result[retu_adc_batt_temp] = 0x0fc;
|
||||
s->result[retu_adc_chg_volt] = 0x165;
|
||||
s->result[retu_adc_head_det] = 123;
|
||||
s->result[retu_adc_hook_det] = 1023;
|
||||
s->result[retu_adc_rf_gp] = 0x11;
|
||||
s->result[retu_adc_tx_det] = 0x11;
|
||||
s->result[retu_adc_batt_volt] = 0x250;
|
||||
s->result[retu_adc_sens] = 2;
|
||||
s->result[retu_adc_sens_temp] = 0x11;
|
||||
s->result[retu_adc_bbatt_volt] = 0x3d0;
|
||||
s->result[retu_adc_self_temp] = 0x330;
|
||||
|
||||
s->cbus.opaque = s;
|
||||
s->cbus.io = retu_io;
|
||||
s->cbus.addr = 1;
|
||||
|
||||
return &s->cbus;
|
||||
}
|
||||
|
||||
void retu_key_event(void *retu, int state)
|
||||
{
|
||||
CBusSlave *slave = (CBusSlave *) retu;
|
||||
CBusRetu *s = (CBusRetu *) slave->opaque;
|
||||
|
||||
s->irqst |= 1 << retu_int_pwr;
|
||||
retu_interrupt_update(s);
|
||||
|
||||
if (state)
|
||||
s->status &= ~(1 << 5);
|
||||
else
|
||||
s->status |= 1 << 5;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void retu_head_event(void *retu, int state)
|
||||
{
|
||||
CBusSlave *slave = (CBusSlave *) retu;
|
||||
CBusRetu *s = (CBusRetu *) slave->opaque;
|
||||
|
||||
if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
|
||||
/* TODO: reissue the interrupt every 100ms or so. */
|
||||
s->irqst |= 1 << retu_int_head;
|
||||
retu_interrupt_update(s);
|
||||
}
|
||||
|
||||
if (state)
|
||||
s->result[retu_adc_head_det] = 50;
|
||||
else
|
||||
s->result[retu_adc_head_det] = 123;
|
||||
}
|
||||
|
||||
static void retu_hook_event(void *retu, int state)
|
||||
{
|
||||
CBusSlave *slave = (CBusSlave *) retu;
|
||||
CBusRetu *s = (CBusRetu *) slave->opaque;
|
||||
|
||||
if ((s->cc[0] & 0x500) == 0x500) {
|
||||
/* TODO: reissue the interrupt every 100ms or so. */
|
||||
s->irqst |= 1 << retu_int_hook;
|
||||
retu_interrupt_update(s);
|
||||
}
|
||||
|
||||
if (state)
|
||||
s->result[retu_adc_hook_det] = 50;
|
||||
else
|
||||
s->result[retu_adc_hook_det] = 123;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Tahvo/Betty */
|
||||
typedef struct {
|
||||
uint16_t irqst;
|
||||
uint16_t irqen;
|
||||
uint8_t charger;
|
||||
uint8_t backlight;
|
||||
uint16_t usbr;
|
||||
uint16_t power;
|
||||
|
||||
int is_betty;
|
||||
qemu_irq irq;
|
||||
CBusSlave cbus;
|
||||
} CBusTahvo;
|
||||
|
||||
static void tahvo_interrupt_update(CBusTahvo *s)
|
||||
{
|
||||
qemu_set_irq(s->irq, s->irqst & ~s->irqen);
|
||||
}
|
||||
|
||||
#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
|
||||
#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
|
||||
#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
|
||||
#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
|
||||
#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
|
||||
#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
|
||||
#define TAHVO_REG_USBR 0x06 /* (RW) USB control */
|
||||
#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
|
||||
#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
|
||||
#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
|
||||
#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
|
||||
#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
|
||||
#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
|
||||
#define TAHVO_REG_FRR 0x0d /* (RO) FR */
|
||||
|
||||
static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("TAHVO read at %02x\n", reg);
|
||||
#endif
|
||||
|
||||
switch (reg) {
|
||||
case TAHVO_REG_ASICR:
|
||||
return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
|
||||
|
||||
case TAHVO_REG_IDR:
|
||||
case TAHVO_REG_IDSR: /* XXX: what does this do? */
|
||||
return s->irqst;
|
||||
|
||||
case TAHVO_REG_IMR:
|
||||
return s->irqen;
|
||||
|
||||
case TAHVO_REG_CHAPWMR:
|
||||
return s->charger;
|
||||
|
||||
case TAHVO_REG_LEDPWMR:
|
||||
return s->backlight;
|
||||
|
||||
case TAHVO_REG_USBR:
|
||||
return s->usbr;
|
||||
|
||||
case TAHVO_REG_RCR:
|
||||
return s->power;
|
||||
|
||||
case TAHVO_REG_CCR1:
|
||||
case TAHVO_REG_CCR2:
|
||||
case TAHVO_REG_TESTR1:
|
||||
case TAHVO_REG_TESTR2:
|
||||
case TAHVO_REG_NOPR:
|
||||
case TAHVO_REG_FRR:
|
||||
return 0x0000;
|
||||
|
||||
default:
|
||||
hw_error("%s: bad register %02x\n", __func__, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("TAHVO write of %04x at %02x\n", val, reg);
|
||||
#endif
|
||||
|
||||
switch (reg) {
|
||||
case TAHVO_REG_IDR:
|
||||
s->irqst ^= val;
|
||||
tahvo_interrupt_update(s);
|
||||
break;
|
||||
|
||||
case TAHVO_REG_IMR:
|
||||
s->irqen = val;
|
||||
tahvo_interrupt_update(s);
|
||||
break;
|
||||
|
||||
case TAHVO_REG_CHAPWMR:
|
||||
s->charger = val;
|
||||
break;
|
||||
|
||||
case TAHVO_REG_LEDPWMR:
|
||||
if (s->backlight != (val & 0x7f)) {
|
||||
s->backlight = val & 0x7f;
|
||||
printf("%s: LCD backlight now at %i / 127\n",
|
||||
__func__, s->backlight);
|
||||
}
|
||||
break;
|
||||
|
||||
case TAHVO_REG_USBR:
|
||||
s->usbr = val;
|
||||
break;
|
||||
|
||||
case TAHVO_REG_RCR:
|
||||
s->power = val;
|
||||
break;
|
||||
|
||||
case TAHVO_REG_CCR1:
|
||||
case TAHVO_REG_CCR2:
|
||||
case TAHVO_REG_TESTR1:
|
||||
case TAHVO_REG_TESTR2:
|
||||
case TAHVO_REG_NOPR:
|
||||
case TAHVO_REG_FRR:
|
||||
break;
|
||||
|
||||
default:
|
||||
hw_error("%s: bad register %02x\n", __func__, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
|
||||
{
|
||||
CBusTahvo *s = (CBusTahvo *) opaque;
|
||||
|
||||
if (rw)
|
||||
*val = tahvo_read(s, reg);
|
||||
else
|
||||
tahvo_write(s, reg, *val);
|
||||
}
|
||||
|
||||
void *tahvo_init(qemu_irq irq, int betty)
|
||||
{
|
||||
CBusTahvo *s = g_malloc0(sizeof(*s));
|
||||
|
||||
s->irq = irq;
|
||||
s->irqen = 0xffff;
|
||||
s->irqst = 0x0000;
|
||||
s->is_betty = !!betty;
|
||||
|
||||
s->cbus.opaque = s;
|
||||
s->cbus.io = tahvo_io;
|
||||
s->cbus.addr = 2;
|
||||
|
||||
return &s->cbus;
|
||||
}
|
|
@ -51,7 +51,6 @@ system_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-ccu.c'
|
|||
system_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-dramc.c'))
|
||||
system_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c'))
|
||||
system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
|
||||
system_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c'))
|
||||
system_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c'))
|
||||
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pmu.c', 'exynos4210_clk.c', 'exynos4210_rng.c'))
|
||||
system_ss.add(when: 'CONFIG_IMX', if_true: files(
|
||||
|
@ -67,7 +66,6 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
|
|||
'imx_ccm.c',
|
||||
'imx_rngc.c',
|
||||
))
|
||||
system_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
|
||||
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
|
||||
'npcm7xx_clk.c',
|
||||
'npcm7xx_gcr.c',
|
||||
|
@ -77,10 +75,6 @@ system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
|
|||
))
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files(
|
||||
'omap_clk.c',
|
||||
'omap_gpmc.c',
|
||||
'omap_l4.c',
|
||||
'omap_sdrc.c',
|
||||
'omap_tap.c',
|
||||
))
|
||||
system_ss.add(when: 'CONFIG_RASPI', if_true: files(
|
||||
'bcm2835_mbox.c',
|
||||
|
|
|
@ -1,269 +0,0 @@
|
|||
/*
|
||||
* PXA270-based Intel Mainstone platforms.
|
||||
* FPGA driver
|
||||
*
|
||||
* Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
|
||||
* <akuster@mvista.com>
|
||||
*
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* Mainstone FPGA for extern irqs */
|
||||
#define FPGA_GPIO_PIN 0
|
||||
#define MST_NUM_IRQS 16
|
||||
#define MST_LEDDAT1 0x10
|
||||
#define MST_LEDDAT2 0x14
|
||||
#define MST_LEDCTRL 0x40
|
||||
#define MST_GPSWR 0x60
|
||||
#define MST_MSCWR1 0x80
|
||||
#define MST_MSCWR2 0x84
|
||||
#define MST_MSCWR3 0x88
|
||||
#define MST_MSCRD 0x90
|
||||
#define MST_INTMSKENA 0xc0
|
||||
#define MST_INTSETCLR 0xd0
|
||||
#define MST_PCMCIA0 0xe0
|
||||
#define MST_PCMCIA1 0xe4
|
||||
|
||||
#define MST_PCMCIAx_READY (1 << 10)
|
||||
#define MST_PCMCIAx_nCD (1 << 5)
|
||||
|
||||
#define MST_PCMCIA_CD0_IRQ 9
|
||||
#define MST_PCMCIA_CD1_IRQ 13
|
||||
|
||||
#define TYPE_MAINSTONE_FPGA "mainstone-fpga"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(mst_irq_state, MAINSTONE_FPGA)
|
||||
|
||||
struct mst_irq_state {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
qemu_irq parent;
|
||||
|
||||
uint32_t prev_level;
|
||||
uint32_t leddat1;
|
||||
uint32_t leddat2;
|
||||
uint32_t ledctrl;
|
||||
uint32_t gpswr;
|
||||
uint32_t mscwr1;
|
||||
uint32_t mscwr2;
|
||||
uint32_t mscwr3;
|
||||
uint32_t mscrd;
|
||||
uint32_t intmskena;
|
||||
uint32_t intsetclr;
|
||||
uint32_t pcmcia0;
|
||||
uint32_t pcmcia1;
|
||||
};
|
||||
|
||||
static void
|
||||
mst_fpga_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
mst_irq_state *s = (mst_irq_state *)opaque;
|
||||
uint32_t oldint = s->intsetclr & s->intmskena;
|
||||
|
||||
if (level)
|
||||
s->prev_level |= 1u << irq;
|
||||
else
|
||||
s->prev_level &= ~(1u << irq);
|
||||
|
||||
switch(irq) {
|
||||
case MST_PCMCIA_CD0_IRQ:
|
||||
if (level)
|
||||
s->pcmcia0 &= ~MST_PCMCIAx_nCD;
|
||||
else
|
||||
s->pcmcia0 |= MST_PCMCIAx_nCD;
|
||||
break;
|
||||
case MST_PCMCIA_CD1_IRQ:
|
||||
if (level)
|
||||
s->pcmcia1 &= ~MST_PCMCIAx_nCD;
|
||||
else
|
||||
s->pcmcia1 |= MST_PCMCIAx_nCD;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((s->intmskena & (1u << irq)) && level)
|
||||
s->intsetclr |= 1u << irq;
|
||||
|
||||
if (oldint != (s->intsetclr & s->intmskena))
|
||||
qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
mst_fpga_readb(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
mst_irq_state *s = (mst_irq_state *) opaque;
|
||||
|
||||
switch (addr) {
|
||||
case MST_LEDDAT1:
|
||||
return s->leddat1;
|
||||
case MST_LEDDAT2:
|
||||
return s->leddat2;
|
||||
case MST_LEDCTRL:
|
||||
return s->ledctrl;
|
||||
case MST_GPSWR:
|
||||
return s->gpswr;
|
||||
case MST_MSCWR1:
|
||||
return s->mscwr1;
|
||||
case MST_MSCWR2:
|
||||
return s->mscwr2;
|
||||
case MST_MSCWR3:
|
||||
return s->mscwr3;
|
||||
case MST_MSCRD:
|
||||
return s->mscrd;
|
||||
case MST_INTMSKENA:
|
||||
return s->intmskena;
|
||||
case MST_INTSETCLR:
|
||||
return s->intsetclr;
|
||||
case MST_PCMCIA0:
|
||||
return s->pcmcia0;
|
||||
case MST_PCMCIA1:
|
||||
return s->pcmcia1;
|
||||
default:
|
||||
printf("Mainstone - mst_fpga_readb: Bad register offset "
|
||||
"0x" HWADDR_FMT_plx "\n", addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
mst_irq_state *s = (mst_irq_state *) opaque;
|
||||
value &= 0xffffffff;
|
||||
|
||||
switch (addr) {
|
||||
case MST_LEDDAT1:
|
||||
s->leddat1 = value;
|
||||
break;
|
||||
case MST_LEDDAT2:
|
||||
s->leddat2 = value;
|
||||
break;
|
||||
case MST_LEDCTRL:
|
||||
s->ledctrl = value;
|
||||
break;
|
||||
case MST_GPSWR:
|
||||
s->gpswr = value;
|
||||
break;
|
||||
case MST_MSCWR1:
|
||||
s->mscwr1 = value;
|
||||
break;
|
||||
case MST_MSCWR2:
|
||||
s->mscwr2 = value;
|
||||
break;
|
||||
case MST_MSCWR3:
|
||||
s->mscwr3 = value;
|
||||
break;
|
||||
case MST_MSCRD:
|
||||
s->mscrd = value;
|
||||
break;
|
||||
case MST_INTMSKENA: /* Mask interrupt */
|
||||
s->intmskena = (value & 0xFEEFF);
|
||||
qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
|
||||
break;
|
||||
case MST_INTSETCLR: /* clear or set interrupt */
|
||||
s->intsetclr = (value & 0xFEEFF);
|
||||
qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
|
||||
break;
|
||||
/* For PCMCIAx allow the to change only power and reset */
|
||||
case MST_PCMCIA0:
|
||||
s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
|
||||
break;
|
||||
case MST_PCMCIA1:
|
||||
s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
|
||||
break;
|
||||
default:
|
||||
printf("Mainstone - mst_fpga_writeb: Bad register offset "
|
||||
"0x" HWADDR_FMT_plx "\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mst_fpga_ops = {
|
||||
.read = mst_fpga_readb,
|
||||
.write = mst_fpga_writeb,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int mst_fpga_post_load(void *opaque, int version_id)
|
||||
{
|
||||
mst_irq_state *s = (mst_irq_state *) opaque;
|
||||
|
||||
qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mst_fpga_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
mst_irq_state *s = MAINSTONE_FPGA(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
|
||||
s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
|
||||
|
||||
sysbus_init_irq(sbd, &s->parent);
|
||||
|
||||
/* alloc the external 16 irqs */
|
||||
qdev_init_gpio_in(dev, mst_fpga_set_irq, MST_NUM_IRQS);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &mst_fpga_ops, s,
|
||||
"fpga", 0x00100000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_mst_fpga_regs = {
|
||||
.name = "mainstone_fpga",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.post_load = mst_fpga_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(prev_level, mst_irq_state),
|
||||
VMSTATE_UINT32(leddat1, mst_irq_state),
|
||||
VMSTATE_UINT32(leddat2, mst_irq_state),
|
||||
VMSTATE_UINT32(ledctrl, mst_irq_state),
|
||||
VMSTATE_UINT32(gpswr, mst_irq_state),
|
||||
VMSTATE_UINT32(mscwr1, mst_irq_state),
|
||||
VMSTATE_UINT32(mscwr2, mst_irq_state),
|
||||
VMSTATE_UINT32(mscwr3, mst_irq_state),
|
||||
VMSTATE_UINT32(mscrd, mst_irq_state),
|
||||
VMSTATE_UINT32(intmskena, mst_irq_state),
|
||||
VMSTATE_UINT32(intsetclr, mst_irq_state),
|
||||
VMSTATE_UINT32(pcmcia0, mst_irq_state),
|
||||
VMSTATE_UINT32(pcmcia1, mst_irq_state),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static void mst_fpga_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "Mainstone II FPGA";
|
||||
dc->vmsd = &vmstate_mst_fpga_regs;
|
||||
}
|
||||
|
||||
static const TypeInfo mst_fpga_info = {
|
||||
.name = TYPE_MAINSTONE_FPGA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(mst_irq_state),
|
||||
.instance_init = mst_fpga_init,
|
||||
.class_init = mst_fpga_class_init,
|
||||
};
|
||||
|
||||
static void mst_fpga_register_types(void)
|
||||
{
|
||||
type_register_static(&mst_fpga_info);
|
||||
}
|
||||
|
||||
type_init(mst_fpga_register_types)
|
|
@ -35,9 +35,6 @@ struct clk {
|
|||
#define CLOCK_IN_OMAP730 (1 << 11)
|
||||
#define CLOCK_IN_OMAP1510 (1 << 12)
|
||||
#define CLOCK_IN_OMAP16XX (1 << 13)
|
||||
#define CLOCK_IN_OMAP242X (1 << 14)
|
||||
#define CLOCK_IN_OMAP243X (1 << 15)
|
||||
#define CLOCK_IN_OMAP343X (1 << 16)
|
||||
uint32_t flags;
|
||||
int id;
|
||||
|
||||
|
@ -59,8 +56,7 @@ static struct clk xtal_osc12m = {
|
|||
static struct clk xtal_osc32k = {
|
||||
.name = "xtal_osc_32k",
|
||||
.rate = 32768,
|
||||
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
|
||||
CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
|
||||
};
|
||||
|
||||
static struct clk ck_ref = {
|
||||
|
@ -507,449 +503,10 @@ static struct clk i2c_ick = {
|
|||
static struct clk clk32k = {
|
||||
.name = "clk32-kHz",
|
||||
.flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
|
||||
CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
ALWAYS_ENABLED,
|
||||
.parent = &xtal_osc32k,
|
||||
};
|
||||
|
||||
static struct clk ref_clk = {
|
||||
.name = "ref_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */
|
||||
/*.parent = sys.xtalin */
|
||||
};
|
||||
|
||||
static struct clk apll_96m = {
|
||||
.name = "apll_96m",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 96000000,
|
||||
/*.parent = ref_clk */
|
||||
};
|
||||
|
||||
static struct clk apll_54m = {
|
||||
.name = "apll_54m",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 54000000,
|
||||
/*.parent = ref_clk */
|
||||
};
|
||||
|
||||
static struct clk sys_clk = {
|
||||
.name = "sys_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 32768,
|
||||
/*.parent = sys.xtalin */
|
||||
};
|
||||
|
||||
static struct clk sleep_clk = {
|
||||
.name = "sleep_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 32768,
|
||||
/*.parent = sys.xtalin */
|
||||
};
|
||||
|
||||
static struct clk dpll_ck = {
|
||||
.name = "dpll",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.parent = &ref_clk,
|
||||
};
|
||||
|
||||
static struct clk dpll_x2_ck = {
|
||||
.name = "dpll_x2",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.parent = &ref_clk,
|
||||
};
|
||||
|
||||
static struct clk wdt1_sys_clk = {
|
||||
.name = "wdt1_sys_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 32768,
|
||||
/*.parent = sys.xtalin */
|
||||
};
|
||||
|
||||
static struct clk func_96m_clk = {
|
||||
.name = "func_96m_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.divisor = 1,
|
||||
.parent = &apll_96m,
|
||||
};
|
||||
|
||||
static struct clk func_48m_clk = {
|
||||
.name = "func_48m_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.divisor = 2,
|
||||
.parent = &apll_96m,
|
||||
};
|
||||
|
||||
static struct clk func_12m_clk = {
|
||||
.name = "func_12m_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.divisor = 8,
|
||||
.parent = &apll_96m,
|
||||
};
|
||||
|
||||
static struct clk func_54m_clk = {
|
||||
.name = "func_54m_clk",
|
||||
.flags = CLOCK_IN_OMAP242X,
|
||||
.divisor = 1,
|
||||
.parent = &apll_54m,
|
||||
};
|
||||
|
||||
static struct clk sys_clkout = {
|
||||
.name = "clkout",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk sys_clkout2 = {
|
||||
.name = "clkout2",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_clk = {
|
||||
.name = "core_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */
|
||||
};
|
||||
|
||||
static struct clk l3_clk = {
|
||||
.name = "l3_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_clk,
|
||||
};
|
||||
|
||||
static struct clk core_l4_iclk = {
|
||||
.name = "core_l4_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &l3_clk,
|
||||
};
|
||||
|
||||
static struct clk wu_l4_iclk = {
|
||||
.name = "wu_l4_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &l3_clk,
|
||||
};
|
||||
|
||||
static struct clk core_l3_iclk = {
|
||||
.name = "core_l3_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_clk,
|
||||
};
|
||||
|
||||
static struct clk core_l4_usb_clk = {
|
||||
.name = "core_l4_usb_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &l3_clk,
|
||||
};
|
||||
|
||||
static struct clk wu_gpt1_clk = {
|
||||
.name = "wu_gpt1_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk wu_32k_clk = {
|
||||
.name = "wu_32k_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk uart1_fclk = {
|
||||
.name = "uart1_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_48m_clk,
|
||||
};
|
||||
|
||||
static struct clk uart1_iclk = {
|
||||
.name = "uart1_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk uart2_fclk = {
|
||||
.name = "uart2_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_48m_clk,
|
||||
};
|
||||
|
||||
static struct clk uart2_iclk = {
|
||||
.name = "uart2_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk uart3_fclk = {
|
||||
.name = "uart3_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_48m_clk,
|
||||
};
|
||||
|
||||
static struct clk uart3_iclk = {
|
||||
.name = "uart3_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk mpu_fclk = {
|
||||
.name = "mpu_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_clk,
|
||||
};
|
||||
|
||||
static struct clk mpu_iclk = {
|
||||
.name = "mpu_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_clk,
|
||||
};
|
||||
|
||||
static struct clk int_m_fclk = {
|
||||
.name = "int_m_fclk",
|
||||
.alias = "mpu_intc_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_clk,
|
||||
};
|
||||
|
||||
static struct clk int_m_iclk = {
|
||||
.name = "int_m_iclk",
|
||||
.alias = "mpu_intc_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt2_clk = {
|
||||
.name = "core_gpt2_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt3_clk = {
|
||||
.name = "core_gpt3_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt4_clk = {
|
||||
.name = "core_gpt4_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt5_clk = {
|
||||
.name = "core_gpt5_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt6_clk = {
|
||||
.name = "core_gpt6_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt7_clk = {
|
||||
.name = "core_gpt7_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt8_clk = {
|
||||
.name = "core_gpt8_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt9_clk = {
|
||||
.name = "core_gpt9_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt10_clk = {
|
||||
.name = "core_gpt10_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt11_clk = {
|
||||
.name = "core_gpt11_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk core_gpt12_clk = {
|
||||
.name = "core_gpt12_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
};
|
||||
|
||||
static struct clk mcbsp1_clk = {
|
||||
.name = "mcbsp1_cg",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.divisor = 2,
|
||||
.parent = &func_96m_clk,
|
||||
};
|
||||
|
||||
static struct clk mcbsp2_clk = {
|
||||
.name = "mcbsp2_cg",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.divisor = 2,
|
||||
.parent = &func_96m_clk,
|
||||
};
|
||||
|
||||
static struct clk emul_clk = {
|
||||
.name = "emul_ck",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_54m_clk,
|
||||
};
|
||||
|
||||
static struct clk sdma_fclk = {
|
||||
.name = "sdma_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &l3_clk,
|
||||
};
|
||||
|
||||
static struct clk sdma_iclk = {
|
||||
.name = "sdma_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l3_iclk, /* core_l4_iclk for the configuration port */
|
||||
};
|
||||
|
||||
static struct clk i2c1_fclk = {
|
||||
.name = "i2c1.fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_12m_clk,
|
||||
.divisor = 1,
|
||||
};
|
||||
|
||||
static struct clk i2c1_iclk = {
|
||||
.name = "i2c1.iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk i2c2_fclk = {
|
||||
.name = "i2c2.fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_12m_clk,
|
||||
.divisor = 1,
|
||||
};
|
||||
|
||||
static struct clk i2c2_iclk = {
|
||||
.name = "i2c2.iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk gpio_dbclk[5] = {
|
||||
{
|
||||
.name = "gpio1_dbclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &wu_32k_clk,
|
||||
}, {
|
||||
.name = "gpio2_dbclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &wu_32k_clk,
|
||||
}, {
|
||||
.name = "gpio3_dbclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &wu_32k_clk,
|
||||
}, {
|
||||
.name = "gpio4_dbclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &wu_32k_clk,
|
||||
}, {
|
||||
.name = "gpio5_dbclk",
|
||||
.flags = CLOCK_IN_OMAP243X,
|
||||
.parent = &wu_32k_clk,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk gpio_iclk = {
|
||||
.name = "gpio_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &wu_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk mmc_fck = {
|
||||
.name = "mmc_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X,
|
||||
.parent = &func_96m_clk,
|
||||
};
|
||||
|
||||
static struct clk mmc_ick = {
|
||||
.name = "mmc_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X,
|
||||
.parent = &core_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk spi_fclk[3] = {
|
||||
{
|
||||
.name = "spi1_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_48m_clk,
|
||||
}, {
|
||||
.name = "spi2_fclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_48m_clk,
|
||||
}, {
|
||||
.name = "spi3_fclk",
|
||||
.flags = CLOCK_IN_OMAP243X,
|
||||
.parent = &func_48m_clk,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk dss_clk[2] = {
|
||||
{
|
||||
.name = "dss_clk1",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_clk,
|
||||
}, {
|
||||
.name = "dss_clk2",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &sys_clk,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk dss_54m_clk = {
|
||||
.name = "dss_54m_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &func_54m_clk,
|
||||
};
|
||||
|
||||
static struct clk dss_l3_iclk = {
|
||||
.name = "dss_l3_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l3_iclk,
|
||||
};
|
||||
|
||||
static struct clk dss_l4_iclk = {
|
||||
.name = "dss_l4_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk spi_iclk[3] = {
|
||||
{
|
||||
.name = "spi1_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
}, {
|
||||
.name = "spi2_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
}, {
|
||||
.name = "spi3_iclk",
|
||||
.flags = CLOCK_IN_OMAP243X,
|
||||
.parent = &core_l4_iclk,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk omapctrl_clk = {
|
||||
.name = "omapctrl_iclk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
/* XXX Should be in WKUP domain */
|
||||
.parent = &core_l4_iclk,
|
||||
};
|
||||
|
||||
static struct clk *onchip_clks[] = {
|
||||
/* OMAP 1 */
|
||||
|
||||
|
@ -1019,80 +576,6 @@ static struct clk *onchip_clks[] = {
|
|||
&i2c_fck,
|
||||
&i2c_ick,
|
||||
|
||||
/* OMAP 2 */
|
||||
|
||||
&ref_clk,
|
||||
&apll_96m,
|
||||
&apll_54m,
|
||||
&sys_clk,
|
||||
&sleep_clk,
|
||||
&dpll_ck,
|
||||
&dpll_x2_ck,
|
||||
&wdt1_sys_clk,
|
||||
&func_96m_clk,
|
||||
&func_48m_clk,
|
||||
&func_12m_clk,
|
||||
&func_54m_clk,
|
||||
&sys_clkout,
|
||||
&sys_clkout2,
|
||||
&core_clk,
|
||||
&l3_clk,
|
||||
&core_l4_iclk,
|
||||
&wu_l4_iclk,
|
||||
&core_l3_iclk,
|
||||
&core_l4_usb_clk,
|
||||
&wu_gpt1_clk,
|
||||
&wu_32k_clk,
|
||||
&uart1_fclk,
|
||||
&uart1_iclk,
|
||||
&uart2_fclk,
|
||||
&uart2_iclk,
|
||||
&uart3_fclk,
|
||||
&uart3_iclk,
|
||||
&mpu_fclk,
|
||||
&mpu_iclk,
|
||||
&int_m_fclk,
|
||||
&int_m_iclk,
|
||||
&core_gpt2_clk,
|
||||
&core_gpt3_clk,
|
||||
&core_gpt4_clk,
|
||||
&core_gpt5_clk,
|
||||
&core_gpt6_clk,
|
||||
&core_gpt7_clk,
|
||||
&core_gpt8_clk,
|
||||
&core_gpt9_clk,
|
||||
&core_gpt10_clk,
|
||||
&core_gpt11_clk,
|
||||
&core_gpt12_clk,
|
||||
&mcbsp1_clk,
|
||||
&mcbsp2_clk,
|
||||
&emul_clk,
|
||||
&sdma_fclk,
|
||||
&sdma_iclk,
|
||||
&i2c1_fclk,
|
||||
&i2c1_iclk,
|
||||
&i2c2_fclk,
|
||||
&i2c2_iclk,
|
||||
&gpio_dbclk[0],
|
||||
&gpio_dbclk[1],
|
||||
&gpio_dbclk[2],
|
||||
&gpio_dbclk[3],
|
||||
&gpio_iclk,
|
||||
&mmc_fck,
|
||||
&mmc_ick,
|
||||
&spi_fclk[0],
|
||||
&spi_iclk[0],
|
||||
&spi_fclk[1],
|
||||
&spi_iclk[1],
|
||||
&spi_fclk[2],
|
||||
&spi_iclk[2],
|
||||
&dss_clk[0],
|
||||
&dss_clk[1],
|
||||
&dss_54m_clk,
|
||||
&dss_l3_iclk,
|
||||
&dss_l4_iclk,
|
||||
&omapctrl_clk,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -1230,12 +713,6 @@ void omap_clk_init(struct omap_mpu_state_s *mpu)
|
|||
flag = CLOCK_IN_OMAP310;
|
||||
else if (cpu_is_omap1510(mpu))
|
||||
flag = CLOCK_IN_OMAP1510;
|
||||
else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu))
|
||||
flag = CLOCK_IN_OMAP242X;
|
||||
else if (cpu_is_omap2430(mpu))
|
||||
flag = CLOCK_IN_OMAP243X;
|
||||
else if (cpu_is_omap3430(mpu))
|
||||
flag = CLOCK_IN_OMAP243X;
|
||||
else
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,898 +0,0 @@
|
|||
/*
|
||||
* TI OMAP general purpose memory controller emulation.
|
||||
*
|
||||
* Copyright (C) 2007-2009 Nokia Corporation
|
||||
* Original code written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
* Enhancements for OMAP3 and NAND support written by Juha Riihimäki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) any later version of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/arm/omap.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
/* General-Purpose Memory Controller */
|
||||
struct omap_gpmc_s {
|
||||
qemu_irq irq;
|
||||
qemu_irq drq;
|
||||
MemoryRegion iomem;
|
||||
int accept_256;
|
||||
|
||||
uint8_t revision;
|
||||
uint8_t sysconfig;
|
||||
uint16_t irqst;
|
||||
uint16_t irqen;
|
||||
uint16_t lastirq;
|
||||
uint16_t timeout;
|
||||
uint16_t config;
|
||||
struct omap_gpmc_cs_file_s {
|
||||
uint32_t config[7];
|
||||
MemoryRegion *iomem;
|
||||
MemoryRegion container;
|
||||
MemoryRegion nandiomem;
|
||||
DeviceState *dev;
|
||||
} cs_file[8];
|
||||
int ecc_cs;
|
||||
int ecc_ptr;
|
||||
uint32_t ecc_cfg;
|
||||
ECCState ecc[9];
|
||||
struct prefetch {
|
||||
uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */
|
||||
uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */
|
||||
int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */
|
||||
int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */
|
||||
int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */
|
||||
MemoryRegion iomem;
|
||||
uint8_t fifo[64];
|
||||
} prefetch;
|
||||
};
|
||||
|
||||
#define OMAP_GPMC_8BIT 0
|
||||
#define OMAP_GPMC_16BIT 1
|
||||
#define OMAP_GPMC_NOR 0
|
||||
#define OMAP_GPMC_NAND 2
|
||||
|
||||
static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f)
|
||||
{
|
||||
return (f->config[0] >> 10) & 3;
|
||||
}
|
||||
|
||||
static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f)
|
||||
{
|
||||
/* devsize field is really 2 bits but we ignore the high
|
||||
* bit to ensure consistent behaviour if the guest sets
|
||||
* it (values 2 and 3 are reserved in the TRM)
|
||||
*/
|
||||
return (f->config[0] >> 12) & 1;
|
||||
}
|
||||
|
||||
/* Extract the chip-select value from the prefetch config1 register */
|
||||
static int prefetch_cs(uint32_t config1)
|
||||
{
|
||||
return (config1 >> 24) & 7;
|
||||
}
|
||||
|
||||
static int prefetch_threshold(uint32_t config1)
|
||||
{
|
||||
return (config1 >> 8) & 0x7f;
|
||||
}
|
||||
|
||||
static void omap_gpmc_int_update(struct omap_gpmc_s *s)
|
||||
{
|
||||
/* The TRM is a bit unclear, but it seems to say that
|
||||
* the TERMINALCOUNTSTATUS bit is set only on the
|
||||
* transition when the prefetch engine goes from
|
||||
* active to inactive, whereas the FIFOEVENTSTATUS
|
||||
* bit is held high as long as the fifo has at
|
||||
* least THRESHOLD bytes available.
|
||||
* So we do the latter here, but TERMINALCOUNTSTATUS
|
||||
* is set elsewhere.
|
||||
*/
|
||||
if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) {
|
||||
s->irqst |= 1;
|
||||
}
|
||||
if ((s->irqen & s->irqst) != s->lastirq) {
|
||||
s->lastirq = s->irqen & s->irqst;
|
||||
qemu_set_irq(s->irq, s->lastirq);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value)
|
||||
{
|
||||
if (s->prefetch.config1 & 4) {
|
||||
qemu_set_irq(s->drq, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Access functions for when a NAND-like device is mapped into memory:
|
||||
* all addresses in the region behave like accesses to the relevant
|
||||
* GPMC_NAND_DATA_i register (which is actually implemented to call these)
|
||||
*/
|
||||
static uint64_t omap_nand_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
struct omap_gpmc_cs_file_s *f = opaque;
|
||||
uint64_t v;
|
||||
nand_setpins(f->dev, 0, 0, 0, 1, 0);
|
||||
switch (omap_gpmc_devsize(f)) {
|
||||
case OMAP_GPMC_8BIT:
|
||||
v = nand_getio(f->dev);
|
||||
if (size == 1) {
|
||||
return v;
|
||||
}
|
||||
v |= (nand_getio(f->dev) << 8);
|
||||
if (size == 2) {
|
||||
return v;
|
||||
}
|
||||
v |= (nand_getio(f->dev) << 16);
|
||||
v |= (nand_getio(f->dev) << 24);
|
||||
return v;
|
||||
case OMAP_GPMC_16BIT:
|
||||
v = nand_getio(f->dev);
|
||||
if (size == 1) {
|
||||
/* 8 bit read from 16 bit device : probably a guest bug */
|
||||
return v & 0xff;
|
||||
}
|
||||
if (size == 2) {
|
||||
return v;
|
||||
}
|
||||
v |= (nand_getio(f->dev) << 16);
|
||||
return v;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_nand_setio(DeviceState *dev, uint64_t value,
|
||||
int nandsize, int size)
|
||||
{
|
||||
/* Write the specified value to the NAND device, respecting
|
||||
* both size of the NAND device and size of the write access.
|
||||
*/
|
||||
switch (nandsize) {
|
||||
case OMAP_GPMC_8BIT:
|
||||
switch (size) {
|
||||
case 1:
|
||||
nand_setio(dev, value & 0xff);
|
||||
break;
|
||||
case 2:
|
||||
nand_setio(dev, value & 0xff);
|
||||
nand_setio(dev, (value >> 8) & 0xff);
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
nand_setio(dev, value & 0xff);
|
||||
nand_setio(dev, (value >> 8) & 0xff);
|
||||
nand_setio(dev, (value >> 16) & 0xff);
|
||||
nand_setio(dev, (value >> 24) & 0xff);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OMAP_GPMC_16BIT:
|
||||
switch (size) {
|
||||
case 1:
|
||||
/* writing to a 16bit device with 8bit access is probably a guest
|
||||
* bug; pass the value through anyway.
|
||||
*/
|
||||
case 2:
|
||||
nand_setio(dev, value & 0xffff);
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
nand_setio(dev, value & 0xffff);
|
||||
nand_setio(dev, (value >> 16) & 0xffff);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_nand_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
struct omap_gpmc_cs_file_s *f = opaque;
|
||||
nand_setpins(f->dev, 0, 0, 0, 1, 0);
|
||||
omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_nand_ops = {
|
||||
.read = omap_nand_read,
|
||||
.write = omap_nand_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void fill_prefetch_fifo(struct omap_gpmc_s *s)
|
||||
{
|
||||
/* Fill the prefetch FIFO by reading data from NAND.
|
||||
* We do this synchronously, unlike the hardware which
|
||||
* will do this asynchronously. We refill when the
|
||||
* FIFO has THRESHOLD bytes free, and we always refill
|
||||
* as much data as possible starting at the top end
|
||||
* of the FIFO.
|
||||
* (We have to refill at THRESHOLD rather than waiting
|
||||
* for the FIFO to empty to allow for the case where
|
||||
* the FIFO size isn't an exact multiple of THRESHOLD
|
||||
* and we're doing DMA transfers.)
|
||||
* This means we never need to handle wrap-around in
|
||||
* the fifo-reading code, and the next byte of data
|
||||
* to read is always fifo[63 - fifopointer].
|
||||
*/
|
||||
int fptr;
|
||||
int cs = prefetch_cs(s->prefetch.config1);
|
||||
int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
|
||||
int bytes;
|
||||
/* Don't believe the bit of the OMAP TRM that says that COUNTVALUE
|
||||
* and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND.
|
||||
* Instead believe the bit that says it is always a byte count.
|
||||
*/
|
||||
bytes = 64 - s->prefetch.fifopointer;
|
||||
if (bytes > s->prefetch.count) {
|
||||
bytes = s->prefetch.count;
|
||||
}
|
||||
if (is16bit) {
|
||||
bytes &= ~1;
|
||||
}
|
||||
|
||||
s->prefetch.count -= bytes;
|
||||
s->prefetch.fifopointer += bytes;
|
||||
fptr = 64 - s->prefetch.fifopointer;
|
||||
/* Move the existing data in the FIFO so it sits just
|
||||
* before what we're about to read in
|
||||
*/
|
||||
while (fptr < (64 - bytes)) {
|
||||
s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes];
|
||||
fptr++;
|
||||
}
|
||||
while (fptr < 64) {
|
||||
if (is16bit) {
|
||||
uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2);
|
||||
s->prefetch.fifo[fptr++] = v & 0xff;
|
||||
s->prefetch.fifo[fptr++] = (v >> 8) & 0xff;
|
||||
} else {
|
||||
s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1);
|
||||
}
|
||||
}
|
||||
if (s->prefetch.startengine && (s->prefetch.count == 0)) {
|
||||
/* This was the final transfer: raise TERMINALCOUNTSTATUS */
|
||||
s->irqst |= 2;
|
||||
s->prefetch.startengine = 0;
|
||||
}
|
||||
/* If there are any bytes in the FIFO at this point then
|
||||
* we must raise a DMA request (either this is a final part
|
||||
* transfer, or we filled the FIFO in which case we certainly
|
||||
* have THRESHOLD bytes available)
|
||||
*/
|
||||
if (s->prefetch.fifopointer != 0) {
|
||||
omap_gpmc_dma_update(s, 1);
|
||||
}
|
||||
omap_gpmc_int_update(s);
|
||||
}
|
||||
|
||||
/* Access functions for a NAND-like device when the prefetch/postwrite
|
||||
* engine is enabled -- all addresses in the region behave alike:
|
||||
* data is read or written to the FIFO.
|
||||
*/
|
||||
static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
struct omap_gpmc_s *s = opaque;
|
||||
uint32_t data;
|
||||
if (s->prefetch.config1 & 1) {
|
||||
/* The TRM doesn't define the behaviour if you read from the
|
||||
* FIFO when the prefetch engine is in write mode. We choose
|
||||
* to always return zero.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
/* Note that trying to read an empty fifo repeats the last byte */
|
||||
if (s->prefetch.fifopointer) {
|
||||
s->prefetch.fifopointer--;
|
||||
}
|
||||
data = s->prefetch.fifo[63 - s->prefetch.fifopointer];
|
||||
if (s->prefetch.fifopointer ==
|
||||
(64 - prefetch_threshold(s->prefetch.config1))) {
|
||||
/* We've drained THRESHOLD bytes now. So deassert the
|
||||
* DMA request, then refill the FIFO (which will probably
|
||||
* assert it again.)
|
||||
*/
|
||||
omap_gpmc_dma_update(s, 0);
|
||||
fill_prefetch_fifo(s);
|
||||
}
|
||||
omap_gpmc_int_update(s);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
struct omap_gpmc_s *s = opaque;
|
||||
int cs = prefetch_cs(s->prefetch.config1);
|
||||
if ((s->prefetch.config1 & 1) == 0) {
|
||||
/* The TRM doesn't define the behaviour of writing to the
|
||||
* FIFO when the prefetch engine is in read mode. We
|
||||
* choose to ignore the write.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
if (s->prefetch.count == 0) {
|
||||
/* The TRM doesn't define the behaviour of writing to the
|
||||
* FIFO if the transfer is complete. We choose to ignore.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
/* The only reason we do any data buffering in postwrite
|
||||
* mode is if we are talking to a 16 bit NAND device, in
|
||||
* which case we need to buffer the first byte of the
|
||||
* 16 bit word until the other byte arrives.
|
||||
*/
|
||||
int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
|
||||
if (is16bit) {
|
||||
/* fifopointer alternates between 64 (waiting for first
|
||||
* byte of word) and 63 (waiting for second byte)
|
||||
*/
|
||||
if (s->prefetch.fifopointer == 64) {
|
||||
s->prefetch.fifo[0] = value;
|
||||
s->prefetch.fifopointer--;
|
||||
} else {
|
||||
value = (value << 8) | s->prefetch.fifo[0];
|
||||
omap_nand_write(&s->cs_file[cs], 0, value, 2);
|
||||
s->prefetch.count--;
|
||||
s->prefetch.fifopointer = 64;
|
||||
}
|
||||
} else {
|
||||
/* Just write the byte : fifopointer remains 64 at all times */
|
||||
omap_nand_write(&s->cs_file[cs], 0, value, 1);
|
||||
s->prefetch.count--;
|
||||
}
|
||||
if (s->prefetch.count == 0) {
|
||||
/* Final transfer: raise TERMINALCOUNTSTATUS */
|
||||
s->irqst |= 2;
|
||||
s->prefetch.startengine = 0;
|
||||
}
|
||||
omap_gpmc_int_update(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_prefetch_ops = {
|
||||
.read = omap_gpmc_prefetch_read,
|
||||
.write = omap_gpmc_prefetch_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 1,
|
||||
};
|
||||
|
||||
static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs)
|
||||
{
|
||||
/* Return the MemoryRegion* to map/unmap for this chipselect */
|
||||
struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
|
||||
if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) {
|
||||
return f->iomem;
|
||||
}
|
||||
if ((s->prefetch.config1 & 0x80) &&
|
||||
(prefetch_cs(s->prefetch.config1) == cs)) {
|
||||
/* The prefetch engine is enabled for this CS: map the FIFO */
|
||||
return &s->prefetch.iomem;
|
||||
}
|
||||
return &f->nandiomem;
|
||||
}
|
||||
|
||||
static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs)
|
||||
{
|
||||
struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
|
||||
uint32_t mask = (f->config[6] >> 8) & 0xf;
|
||||
uint32_t base = f->config[6] & 0x3f;
|
||||
uint32_t size;
|
||||
|
||||
if (!f->iomem && !f->dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(f->config[6] & (1 << 6))) {
|
||||
/* Do nothing unless CSVALID */
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: check for overlapping regions and report access errors */
|
||||
if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf
|
||||
&& !(s->accept_256 && !mask)) {
|
||||
fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n",
|
||||
__func__, mask);
|
||||
}
|
||||
|
||||
base <<= 24;
|
||||
size = (0x0fffffff & ~(mask << 24)) + 1;
|
||||
/* TODO: rather than setting the size of the mapping (which should be
|
||||
* constant), the mask should cause wrapping of the address space, so
|
||||
* that the same memory becomes accessible at every <i>size</i> bytes
|
||||
* starting from <i>base</i>. */
|
||||
memory_region_init(&f->container, NULL, "omap-gpmc-file", size);
|
||||
memory_region_add_subregion(&f->container, 0,
|
||||
omap_gpmc_cs_memregion(s, cs));
|
||||
memory_region_add_subregion(get_system_memory(), base,
|
||||
&f->container);
|
||||
}
|
||||
|
||||
static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs)
|
||||
{
|
||||
struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
|
||||
if (!(f->config[6] & (1 << 6))) {
|
||||
/* Do nothing unless CSVALID */
|
||||
return;
|
||||
}
|
||||
if (!f->iomem && !f->dev) {
|
||||
return;
|
||||
}
|
||||
memory_region_del_subregion(get_system_memory(), &f->container);
|
||||
memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs));
|
||||
object_unparent(OBJECT(&f->container));
|
||||
}
|
||||
|
||||
void omap_gpmc_reset(struct omap_gpmc_s *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
s->sysconfig = 0;
|
||||
s->irqst = 0;
|
||||
s->irqen = 0;
|
||||
omap_gpmc_int_update(s);
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* This has to happen before we change any of the config
|
||||
* used to determine which memory regions are mapped or unmapped.
|
||||
*/
|
||||
omap_gpmc_cs_unmap(s, i);
|
||||
}
|
||||
s->timeout = 0;
|
||||
s->config = 0xa00;
|
||||
s->prefetch.config1 = 0x00004000;
|
||||
s->prefetch.transfercount = 0x00000000;
|
||||
s->prefetch.startengine = 0;
|
||||
s->prefetch.fifopointer = 0;
|
||||
s->prefetch.count = 0;
|
||||
for (i = 0; i < 8; i ++) {
|
||||
s->cs_file[i].config[1] = 0x101001;
|
||||
s->cs_file[i].config[2] = 0x020201;
|
||||
s->cs_file[i].config[3] = 0x10031003;
|
||||
s->cs_file[i].config[4] = 0x10f1111;
|
||||
s->cs_file[i].config[5] = 0;
|
||||
s->cs_file[i].config[6] = 0xf00;
|
||||
/* In theory we could probe attached devices for some CFG1
|
||||
* bits here, but we just retain them across resets as they
|
||||
* were set initially by omap_gpmc_attach().
|
||||
*/
|
||||
if (i == 0) {
|
||||
s->cs_file[i].config[0] &= 0x00433e00;
|
||||
s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */
|
||||
omap_gpmc_cs_map(s, i);
|
||||
} else {
|
||||
s->cs_file[i].config[0] &= 0x00403c00;
|
||||
}
|
||||
}
|
||||
s->ecc_cs = 0;
|
||||
s->ecc_ptr = 0;
|
||||
s->ecc_cfg = 0x3fcff000;
|
||||
for (i = 0; i < 9; i ++)
|
||||
ecc_reset(&s->ecc[i]);
|
||||
}
|
||||
|
||||
static int gpmc_wordaccess_only(hwaddr addr)
|
||||
{
|
||||
/* Return true if the register offset is to a register that
|
||||
* only permits word width accesses.
|
||||
* Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND
|
||||
* for any chipselect.
|
||||
*/
|
||||
if (addr >= 0x60 && addr <= 0x1d4) {
|
||||
int cs = (addr - 0x60) / 0x30;
|
||||
addr -= cs * 0x30;
|
||||
if (addr >= 0x7c && addr < 0x88) {
|
||||
/* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint64_t omap_gpmc_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
struct omap_gpmc_s *s = opaque;
|
||||
int cs;
|
||||
struct omap_gpmc_cs_file_s *f;
|
||||
|
||||
if (size != 4 && gpmc_wordaccess_only(addr)) {
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x000: /* GPMC_REVISION */
|
||||
return s->revision;
|
||||
|
||||
case 0x010: /* GPMC_SYSCONFIG */
|
||||
return s->sysconfig;
|
||||
|
||||
case 0x014: /* GPMC_SYSSTATUS */
|
||||
return 1; /* RESETDONE */
|
||||
|
||||
case 0x018: /* GPMC_IRQSTATUS */
|
||||
return s->irqst;
|
||||
|
||||
case 0x01c: /* GPMC_IRQENABLE */
|
||||
return s->irqen;
|
||||
|
||||
case 0x040: /* GPMC_TIMEOUT_CONTROL */
|
||||
return s->timeout;
|
||||
|
||||
case 0x044: /* GPMC_ERR_ADDRESS */
|
||||
case 0x048: /* GPMC_ERR_TYPE */
|
||||
return 0;
|
||||
|
||||
case 0x050: /* GPMC_CONFIG */
|
||||
return s->config;
|
||||
|
||||
case 0x054: /* GPMC_STATUS */
|
||||
return 0x001;
|
||||
|
||||
case 0x060 ... 0x1d4:
|
||||
cs = (addr - 0x060) / 0x30;
|
||||
addr -= cs * 0x30;
|
||||
f = s->cs_file + cs;
|
||||
switch (addr) {
|
||||
case 0x60: /* GPMC_CONFIG1 */
|
||||
return f->config[0];
|
||||
case 0x64: /* GPMC_CONFIG2 */
|
||||
return f->config[1];
|
||||
case 0x68: /* GPMC_CONFIG3 */
|
||||
return f->config[2];
|
||||
case 0x6c: /* GPMC_CONFIG4 */
|
||||
return f->config[3];
|
||||
case 0x70: /* GPMC_CONFIG5 */
|
||||
return f->config[4];
|
||||
case 0x74: /* GPMC_CONFIG6 */
|
||||
return f->config[5];
|
||||
case 0x78: /* GPMC_CONFIG7 */
|
||||
return f->config[6];
|
||||
case 0x84 ... 0x87: /* GPMC_NAND_DATA */
|
||||
if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
|
||||
return omap_nand_read(f, 0, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
|
||||
return s->prefetch.config1;
|
||||
case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */
|
||||
return s->prefetch.transfercount;
|
||||
case 0x1ec: /* GPMC_PREFETCH_CONTROL */
|
||||
return s->prefetch.startengine;
|
||||
case 0x1f0: /* GPMC_PREFETCH_STATUS */
|
||||
/* NB: The OMAP3 TRM is inconsistent about whether the GPMC
|
||||
* FIFOTHRESHOLDSTATUS bit should be set when
|
||||
* FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
|
||||
* Apparently the underlying functional spec from which the TRM was
|
||||
* created states that the behaviour is ">=", and this also
|
||||
* makes more conceptual sense.
|
||||
*/
|
||||
return (s->prefetch.fifopointer << 24) |
|
||||
((s->prefetch.fifopointer >=
|
||||
((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
|
||||
s->prefetch.count;
|
||||
|
||||
case 0x1f4: /* GPMC_ECC_CONFIG */
|
||||
return s->ecc_cs;
|
||||
case 0x1f8: /* GPMC_ECC_CONTROL */
|
||||
return s->ecc_ptr;
|
||||
case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */
|
||||
return s->ecc_cfg;
|
||||
case 0x200 ... 0x220: /* GPMC_ECC_RESULT */
|
||||
cs = (addr & 0x1f) >> 2;
|
||||
/* TODO: check correctness */
|
||||
return
|
||||
((s->ecc[cs].cp & 0x07) << 0) |
|
||||
((s->ecc[cs].cp & 0x38) << 13) |
|
||||
((s->ecc[cs].lp[0] & 0x1ff) << 3) |
|
||||
((s->ecc[cs].lp[1] & 0x1ff) << 19);
|
||||
|
||||
case 0x230: /* GPMC_TESTMODE_CTRL */
|
||||
return 0;
|
||||
case 0x234: /* GPMC_PSA_LSB */
|
||||
case 0x238: /* GPMC_PSA_MSB */
|
||||
return 0x00000000;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_gpmc_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
struct omap_gpmc_s *s = opaque;
|
||||
int cs;
|
||||
struct omap_gpmc_cs_file_s *f;
|
||||
|
||||
if (size != 4 && gpmc_wordaccess_only(addr)) {
|
||||
omap_badwidth_write32(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x000: /* GPMC_REVISION */
|
||||
case 0x014: /* GPMC_SYSSTATUS */
|
||||
case 0x054: /* GPMC_STATUS */
|
||||
case 0x1f0: /* GPMC_PREFETCH_STATUS */
|
||||
case 0x200 ... 0x220: /* GPMC_ECC_RESULT */
|
||||
case 0x234: /* GPMC_PSA_LSB */
|
||||
case 0x238: /* GPMC_PSA_MSB */
|
||||
OMAP_RO_REG(addr);
|
||||
break;
|
||||
|
||||
case 0x010: /* GPMC_SYSCONFIG */
|
||||
if ((value >> 3) == 0x3)
|
||||
fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n",
|
||||
__func__, value >> 3);
|
||||
if (value & 2)
|
||||
omap_gpmc_reset(s);
|
||||
s->sysconfig = value & 0x19;
|
||||
break;
|
||||
|
||||
case 0x018: /* GPMC_IRQSTATUS */
|
||||
s->irqst &= ~value;
|
||||
omap_gpmc_int_update(s);
|
||||
break;
|
||||
|
||||
case 0x01c: /* GPMC_IRQENABLE */
|
||||
s->irqen = value & 0xf03;
|
||||
omap_gpmc_int_update(s);
|
||||
break;
|
||||
|
||||
case 0x040: /* GPMC_TIMEOUT_CONTROL */
|
||||
s->timeout = value & 0x1ff1;
|
||||
break;
|
||||
|
||||
case 0x044: /* GPMC_ERR_ADDRESS */
|
||||
case 0x048: /* GPMC_ERR_TYPE */
|
||||
break;
|
||||
|
||||
case 0x050: /* GPMC_CONFIG */
|
||||
s->config = value & 0xf13;
|
||||
break;
|
||||
|
||||
case 0x060 ... 0x1d4:
|
||||
cs = (addr - 0x060) / 0x30;
|
||||
addr -= cs * 0x30;
|
||||
f = s->cs_file + cs;
|
||||
switch (addr) {
|
||||
case 0x60: /* GPMC_CONFIG1 */
|
||||
f->config[0] = value & 0xffef3e13;
|
||||
break;
|
||||
case 0x64: /* GPMC_CONFIG2 */
|
||||
f->config[1] = value & 0x001f1f8f;
|
||||
break;
|
||||
case 0x68: /* GPMC_CONFIG3 */
|
||||
f->config[2] = value & 0x001f1f8f;
|
||||
break;
|
||||
case 0x6c: /* GPMC_CONFIG4 */
|
||||
f->config[3] = value & 0x1f8f1f8f;
|
||||
break;
|
||||
case 0x70: /* GPMC_CONFIG5 */
|
||||
f->config[4] = value & 0x0f1f1f1f;
|
||||
break;
|
||||
case 0x74: /* GPMC_CONFIG6 */
|
||||
f->config[5] = value & 0x00000fcf;
|
||||
break;
|
||||
case 0x78: /* GPMC_CONFIG7 */
|
||||
if ((f->config[6] ^ value) & 0xf7f) {
|
||||
omap_gpmc_cs_unmap(s, cs);
|
||||
f->config[6] = value & 0x00000f7f;
|
||||
omap_gpmc_cs_map(s, cs);
|
||||
}
|
||||
break;
|
||||
case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */
|
||||
if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
|
||||
nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */
|
||||
omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
|
||||
}
|
||||
break;
|
||||
case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */
|
||||
if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
|
||||
nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */
|
||||
omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
|
||||
}
|
||||
break;
|
||||
case 0x84 ... 0x87: /* GPMC_NAND_DATA */
|
||||
if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
|
||||
omap_nand_write(f, 0, value, size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto bad_reg;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
|
||||
if (!s->prefetch.startengine) {
|
||||
uint32_t newconfig1 = value & 0x7f8f7fbf;
|
||||
uint32_t changed;
|
||||
changed = newconfig1 ^ s->prefetch.config1;
|
||||
if (changed & (0x80 | 0x7000000)) {
|
||||
/* Turning the engine on or off, or mapping it somewhere else.
|
||||
* cs_map() and cs_unmap() check the prefetch config and
|
||||
* overall CSVALID bits, so it is sufficient to unmap-and-map
|
||||
* both the old cs and the new one. Note that we adhere to
|
||||
* the "unmap/change config/map" order (and not unmap twice
|
||||
* if newcs == oldcs), otherwise we'll try to delete the wrong
|
||||
* memory region.
|
||||
*/
|
||||
int oldcs = prefetch_cs(s->prefetch.config1);
|
||||
int newcs = prefetch_cs(newconfig1);
|
||||
omap_gpmc_cs_unmap(s, oldcs);
|
||||
if (oldcs != newcs) {
|
||||
omap_gpmc_cs_unmap(s, newcs);
|
||||
}
|
||||
s->prefetch.config1 = newconfig1;
|
||||
omap_gpmc_cs_map(s, oldcs);
|
||||
if (oldcs != newcs) {
|
||||
omap_gpmc_cs_map(s, newcs);
|
||||
}
|
||||
} else {
|
||||
s->prefetch.config1 = newconfig1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */
|
||||
if (!s->prefetch.startengine) {
|
||||
s->prefetch.transfercount = value & 0x3fff;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1ec: /* GPMC_PREFETCH_CONTROL */
|
||||
if (s->prefetch.startengine != (value & 1)) {
|
||||
s->prefetch.startengine = value & 1;
|
||||
if (s->prefetch.startengine) {
|
||||
/* Prefetch engine start */
|
||||
s->prefetch.count = s->prefetch.transfercount;
|
||||
if (s->prefetch.config1 & 1) {
|
||||
/* Write */
|
||||
s->prefetch.fifopointer = 64;
|
||||
} else {
|
||||
/* Read */
|
||||
s->prefetch.fifopointer = 0;
|
||||
fill_prefetch_fifo(s);
|
||||
}
|
||||
} else {
|
||||
/* Prefetch engine forcibly stopped. The TRM
|
||||
* doesn't define the behaviour if you do this.
|
||||
* We clear the prefetch count, which means that
|
||||
* we permit no more writes, and don't read any
|
||||
* more data from NAND. The CPU can still drain
|
||||
* the FIFO of unread data.
|
||||
*/
|
||||
s->prefetch.count = 0;
|
||||
}
|
||||
omap_gpmc_int_update(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1f4: /* GPMC_ECC_CONFIG */
|
||||
s->ecc_cs = 0x8f;
|
||||
break;
|
||||
case 0x1f8: /* GPMC_ECC_CONTROL */
|
||||
if (value & (1 << 8))
|
||||
for (cs = 0; cs < 9; cs ++)
|
||||
ecc_reset(&s->ecc[cs]);
|
||||
s->ecc_ptr = value & 0xf;
|
||||
if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
|
||||
s->ecc_ptr = 0;
|
||||
s->ecc_cs &= ~1;
|
||||
}
|
||||
break;
|
||||
case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */
|
||||
s->ecc_cfg = value & 0x3fcff1ff;
|
||||
break;
|
||||
case 0x230: /* GPMC_TESTMODE_CTRL */
|
||||
if (value & 7)
|
||||
fprintf(stderr, "%s: test mode enable attempt\n", __func__);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_reg:
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_gpmc_ops = {
|
||||
.read = omap_gpmc_read,
|
||||
.write = omap_gpmc_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
|
||||
hwaddr base,
|
||||
qemu_irq irq, qemu_irq drq)
|
||||
{
|
||||
int cs;
|
||||
struct omap_gpmc_s *s = g_new0(struct omap_gpmc_s, 1);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
|
||||
memory_region_add_subregion(get_system_memory(), base, &s->iomem);
|
||||
|
||||
s->irq = irq;
|
||||
s->drq = drq;
|
||||
s->accept_256 = cpu_is_omap3630(mpu);
|
||||
s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
|
||||
s->lastirq = 0;
|
||||
omap_gpmc_reset(s);
|
||||
|
||||
/* We have to register a different IO memory handler for each
|
||||
* chip select region in case a NAND device is mapped there. We
|
||||
* make the region the worst-case size of 256MB and rely on the
|
||||
* container memory region in cs_map to chop it down to the actual
|
||||
* guest-requested size.
|
||||
*/
|
||||
for (cs = 0; cs < 8; cs++) {
|
||||
memory_region_init_io(&s->cs_file[cs].nandiomem, NULL,
|
||||
&omap_nand_ops,
|
||||
&s->cs_file[cs],
|
||||
"omap-nand",
|
||||
256 * 1024 * 1024);
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->prefetch.iomem, NULL, &omap_prefetch_ops, s,
|
||||
"omap-gpmc-prefetch", 256 * 1024 * 1024);
|
||||
return s;
|
||||
}
|
||||
|
||||
void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem)
|
||||
{
|
||||
struct omap_gpmc_cs_file_s *f;
|
||||
assert(iomem);
|
||||
|
||||
if (cs < 0 || cs >= 8) {
|
||||
fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
|
||||
exit(-1);
|
||||
}
|
||||
f = &s->cs_file[cs];
|
||||
|
||||
omap_gpmc_cs_unmap(s, cs);
|
||||
f->config[0] &= ~(0xf << 10);
|
||||
f->iomem = iomem;
|
||||
omap_gpmc_cs_map(s, cs);
|
||||
}
|
||||
|
||||
void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand)
|
||||
{
|
||||
struct omap_gpmc_cs_file_s *f;
|
||||
assert(nand);
|
||||
|
||||
if (cs < 0 || cs >= 8) {
|
||||
fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
|
||||
exit(-1);
|
||||
}
|
||||
f = &s->cs_file[cs];
|
||||
|
||||
omap_gpmc_cs_unmap(s, cs);
|
||||
f->config[0] &= ~(0xf << 10);
|
||||
f->config[0] |= (OMAP_GPMC_NAND << 10);
|
||||
f->dev = nand;
|
||||
if (nand_getbuswidth(f->dev) == 16) {
|
||||
f->config[0] |= OMAP_GPMC_16BIT << 12;
|
||||
}
|
||||
omap_gpmc_cs_map(s, cs);
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
* TI OMAP L4 interconnect emulation.
|
||||
*
|
||||
* Copyright (C) 2007-2009 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) any later version of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/arm/omap.h"
|
||||
|
||||
struct omap_l4_s {
|
||||
MemoryRegion *address_space;
|
||||
hwaddr base;
|
||||
int ta_num;
|
||||
struct omap_target_agent_s ta[];
|
||||
};
|
||||
|
||||
struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
|
||||
hwaddr base, int ta_num)
|
||||
{
|
||||
struct omap_l4_s *bus = g_malloc0(
|
||||
sizeof(*bus) + ta_num * sizeof(*bus->ta));
|
||||
|
||||
bus->address_space = address_space;
|
||||
bus->ta_num = ta_num;
|
||||
bus->base = base;
|
||||
|
||||
return bus;
|
||||
}
|
||||
|
||||
hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
|
||||
int region)
|
||||
{
|
||||
return ta->bus->base + ta->start[region].offset;
|
||||
}
|
||||
|
||||
hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
|
||||
int region)
|
||||
{
|
||||
return ta->start[region].size;
|
||||
}
|
||||
|
||||
static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
struct omap_target_agent_s *s = opaque;
|
||||
|
||||
if (size != 2) {
|
||||
return omap_badwidth_read16(opaque, addr);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* COMPONENT */
|
||||
return s->component;
|
||||
|
||||
case 0x20: /* AGENT_CONTROL */
|
||||
return s->control;
|
||||
|
||||
case 0x28: /* AGENT_STATUS */
|
||||
return s->status;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_l4ta_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
struct omap_target_agent_s *s = opaque;
|
||||
|
||||
if (size != 4) {
|
||||
omap_badwidth_write32(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* COMPONENT */
|
||||
case 0x28: /* AGENT_STATUS */
|
||||
OMAP_RO_REG(addr);
|
||||
break;
|
||||
|
||||
case 0x20: /* AGENT_CONTROL */
|
||||
s->control = value & 0x01000700;
|
||||
if (value & 1) /* OCP_RESET */
|
||||
s->status &= ~1; /* REQ_TIMEOUT */
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_l4ta_ops = {
|
||||
.read = omap_l4ta_read,
|
||||
.write = omap_l4ta_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
|
||||
const struct omap_l4_region_s *regions,
|
||||
const struct omap_l4_agent_info_s *agents,
|
||||
int cs)
|
||||
{
|
||||
int i;
|
||||
struct omap_target_agent_s *ta = NULL;
|
||||
const struct omap_l4_agent_info_s *info = NULL;
|
||||
|
||||
for (i = 0; i < bus->ta_num; i ++)
|
||||
if (agents[i].ta == cs) {
|
||||
ta = &bus->ta[i];
|
||||
info = &agents[i];
|
||||
break;
|
||||
}
|
||||
if (!ta) {
|
||||
fprintf(stderr, "%s: bad target agent (%i)\n", __func__, cs);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ta->bus = bus;
|
||||
ta->start = ®ions[info->region];
|
||||
ta->regions = info->regions;
|
||||
|
||||
ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
|
||||
ta->status = 0x00000000;
|
||||
ta->control = 0x00000200; /* XXX 01000200 for L4TAO */
|
||||
|
||||
memory_region_init_io(&ta->iomem, NULL, &omap_l4ta_ops, ta, "omap.l4ta",
|
||||
omap_l4_region_size(ta, info->ta_region));
|
||||
omap_l4_attach(ta, info->ta_region, &ta->iomem);
|
||||
|
||||
return ta;
|
||||
}
|
||||
|
||||
hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
|
||||
int region, MemoryRegion *mr)
|
||||
{
|
||||
hwaddr base;
|
||||
|
||||
if (region < 0 || region >= ta->regions) {
|
||||
fprintf(stderr, "%s: bad io region (%i)\n", __func__, region);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
base = ta->bus->base + ta->start[region].offset;
|
||||
if (mr) {
|
||||
memory_region_add_subregion(ta->bus->address_space, base, mr);
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* TI OMAP SDRAM controller emulation.
|
||||
*
|
||||
* Copyright (C) 2007-2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) any later version of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/arm/omap.h"
|
||||
|
||||
/* SDRAM Controller Subsystem */
|
||||
struct omap_sdrc_s {
|
||||
MemoryRegion iomem;
|
||||
uint8_t config;
|
||||
};
|
||||
|
||||
void omap_sdrc_reset(struct omap_sdrc_s *s)
|
||||
{
|
||||
s->config = 0x10;
|
||||
}
|
||||
|
||||
static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
struct omap_sdrc_s *s = opaque;
|
||||
|
||||
if (size != 4) {
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* SDRC_REVISION */
|
||||
return 0x20;
|
||||
|
||||
case 0x10: /* SDRC_SYSCONFIG */
|
||||
return s->config;
|
||||
|
||||
case 0x14: /* SDRC_SYSSTATUS */
|
||||
return 1; /* RESETDONE */
|
||||
|
||||
case 0x40: /* SDRC_CS_CFG */
|
||||
case 0x44: /* SDRC_SHARING */
|
||||
case 0x48: /* SDRC_ERR_ADDR */
|
||||
case 0x4c: /* SDRC_ERR_TYPE */
|
||||
case 0x60: /* SDRC_DLLA_SCTRL */
|
||||
case 0x64: /* SDRC_DLLA_STATUS */
|
||||
case 0x68: /* SDRC_DLLB_CTRL */
|
||||
case 0x6c: /* SDRC_DLLB_STATUS */
|
||||
case 0x70: /* SDRC_POWER */
|
||||
case 0x80: /* SDRC_MCFG_0 */
|
||||
case 0x84: /* SDRC_MR_0 */
|
||||
case 0x88: /* SDRC_EMR1_0 */
|
||||
case 0x8c: /* SDRC_EMR2_0 */
|
||||
case 0x90: /* SDRC_EMR3_0 */
|
||||
case 0x94: /* SDRC_DCDL1_CTRL */
|
||||
case 0x98: /* SDRC_DCDL2_CTRL */
|
||||
case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
|
||||
case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
|
||||
case 0xa4: /* SDRC_RFR_CTRL_0 */
|
||||
case 0xa8: /* SDRC_MANUAL_0 */
|
||||
case 0xb0: /* SDRC_MCFG_1 */
|
||||
case 0xb4: /* SDRC_MR_1 */
|
||||
case 0xb8: /* SDRC_EMR1_1 */
|
||||
case 0xbc: /* SDRC_EMR2_1 */
|
||||
case 0xc0: /* SDRC_EMR3_1 */
|
||||
case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
|
||||
case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
|
||||
case 0xd4: /* SDRC_RFR_CTRL_1 */
|
||||
case 0xd8: /* SDRC_MANUAL_1 */
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_sdrc_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
struct omap_sdrc_s *s = opaque;
|
||||
|
||||
if (size != 4) {
|
||||
omap_badwidth_write32(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* SDRC_REVISION */
|
||||
case 0x14: /* SDRC_SYSSTATUS */
|
||||
case 0x48: /* SDRC_ERR_ADDR */
|
||||
case 0x64: /* SDRC_DLLA_STATUS */
|
||||
case 0x6c: /* SDRC_DLLB_STATUS */
|
||||
OMAP_RO_REG(addr);
|
||||
return;
|
||||
|
||||
case 0x10: /* SDRC_SYSCONFIG */
|
||||
if ((value >> 3) != 0x2)
|
||||
fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
|
||||
__func__, (unsigned)value >> 3);
|
||||
if (value & 2)
|
||||
omap_sdrc_reset(s);
|
||||
s->config = value & 0x18;
|
||||
break;
|
||||
|
||||
case 0x40: /* SDRC_CS_CFG */
|
||||
case 0x44: /* SDRC_SHARING */
|
||||
case 0x4c: /* SDRC_ERR_TYPE */
|
||||
case 0x60: /* SDRC_DLLA_SCTRL */
|
||||
case 0x68: /* SDRC_DLLB_CTRL */
|
||||
case 0x70: /* SDRC_POWER */
|
||||
case 0x80: /* SDRC_MCFG_0 */
|
||||
case 0x84: /* SDRC_MR_0 */
|
||||
case 0x88: /* SDRC_EMR1_0 */
|
||||
case 0x8c: /* SDRC_EMR2_0 */
|
||||
case 0x90: /* SDRC_EMR3_0 */
|
||||
case 0x94: /* SDRC_DCDL1_CTRL */
|
||||
case 0x98: /* SDRC_DCDL2_CTRL */
|
||||
case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
|
||||
case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
|
||||
case 0xa4: /* SDRC_RFR_CTRL_0 */
|
||||
case 0xa8: /* SDRC_MANUAL_0 */
|
||||
case 0xb0: /* SDRC_MCFG_1 */
|
||||
case 0xb4: /* SDRC_MR_1 */
|
||||
case 0xb8: /* SDRC_EMR1_1 */
|
||||
case 0xbc: /* SDRC_EMR2_1 */
|
||||
case 0xc0: /* SDRC_EMR3_1 */
|
||||
case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
|
||||
case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
|
||||
case 0xd4: /* SDRC_RFR_CTRL_1 */
|
||||
case 0xd8: /* SDRC_MANUAL_1 */
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_sdrc_ops = {
|
||||
.read = omap_sdrc_read,
|
||||
.write = omap_sdrc_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
|
||||
hwaddr base)
|
||||
{
|
||||
struct omap_sdrc_s *s = g_new0(struct omap_sdrc_s, 1);
|
||||
|
||||
omap_sdrc_reset(s);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_sdrc_ops, s, "omap.sdrc", 0x1000);
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
|
||||
return s;
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* TI OMAP TEST-Chip-level TAP emulation.
|
||||
*
|
||||
* Copyright (C) 2007-2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) any later version of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/omap.h"
|
||||
|
||||
/* TEST-Chip-level TAP */
|
||||
static uint64_t omap_tap_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
struct omap_mpu_state_s *s = opaque;
|
||||
|
||||
if (size != 4) {
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x204: /* IDCODE_reg */
|
||||
switch (s->mpu_model) {
|
||||
case omap2420:
|
||||
case omap2422:
|
||||
case omap2423:
|
||||
return 0x5b5d902f; /* ES 2.2 */
|
||||
case omap2430:
|
||||
return 0x5b68a02f; /* ES 2.2 */
|
||||
case omap3430:
|
||||
return 0x1b7ae02f; /* ES 2 */
|
||||
default:
|
||||
hw_error("%s: Bad mpu model\n", __func__);
|
||||
}
|
||||
|
||||
case 0x208: /* PRODUCTION_ID_reg for OMAP2 */
|
||||
case 0x210: /* PRODUCTION_ID_reg for OMAP3 */
|
||||
switch (s->mpu_model) {
|
||||
case omap2420:
|
||||
return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */
|
||||
case omap2422:
|
||||
return 0x000400f0;
|
||||
case omap2423:
|
||||
return 0x000800f0;
|
||||
case omap2430:
|
||||
return 0x000000f0;
|
||||
case omap3430:
|
||||
return 0x000000f0;
|
||||
default:
|
||||
hw_error("%s: Bad mpu model\n", __func__);
|
||||
}
|
||||
|
||||
case 0x20c:
|
||||
switch (s->mpu_model) {
|
||||
case omap2420:
|
||||
case omap2422:
|
||||
case omap2423:
|
||||
return 0xcafeb5d9; /* ES 2.2 */
|
||||
case omap2430:
|
||||
return 0xcafeb68a; /* ES 2.2 */
|
||||
case omap3430:
|
||||
return 0xcafeb7ae; /* ES 2 */
|
||||
default:
|
||||
hw_error("%s: Bad mpu model\n", __func__);
|
||||
}
|
||||
|
||||
case 0x218: /* DIE_ID_reg */
|
||||
return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
|
||||
case 0x21c: /* DIE_ID_reg */
|
||||
return 0x54 << 24;
|
||||
case 0x220: /* DIE_ID_reg */
|
||||
return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
|
||||
case 0x224: /* DIE_ID_reg */
|
||||
return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_tap_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
if (size != 4) {
|
||||
omap_badwidth_write32(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_tap_ops = {
|
||||
.read = omap_tap_read,
|
||||
.write = omap_tap_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
void omap_tap_init(struct omap_target_agent_s *ta,
|
||||
struct omap_mpu_state_s *mpu)
|
||||
{
|
||||
memory_region_init_io(&mpu->tap_iomem, NULL, &omap_tap_ops, mpu, "omap.tap",
|
||||
omap_l4_region_size(ta, 0));
|
||||
omap_l4_attach(ta, 0, &mpu->tap_iomem);
|
||||
}
|
|
@ -1,2 +1 @@
|
|||
system_ss.add(when: 'CONFIG_PCMCIA', if_true: files('pcmcia.c'))
|
||||
system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx.c'))
|
||||
|
|
|
@ -1,248 +0,0 @@
|
|||
/*
|
||||
* Intel XScale PXA255/270 PC Card and CompactFlash Interface.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GPLv2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/pcmcia.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
|
||||
struct PXA2xxPCMCIAState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
PCMCIASocket slot;
|
||||
MemoryRegion container_mem;
|
||||
MemoryRegion common_iomem;
|
||||
MemoryRegion attr_iomem;
|
||||
MemoryRegion iomem;
|
||||
|
||||
qemu_irq irq;
|
||||
qemu_irq cd_irq;
|
||||
|
||||
PCMCIACardState *card;
|
||||
};
|
||||
|
||||
static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
|
||||
hwaddr offset, unsigned size)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
PCMCIACardClass *pcc;
|
||||
|
||||
if (s->slot.attached) {
|
||||
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
||||
return pcc->common_read(s->card, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
PCMCIACardClass *pcc;
|
||||
|
||||
if (s->slot.attached) {
|
||||
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
||||
pcc->common_write(s->card, offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
|
||||
hwaddr offset, unsigned size)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
PCMCIACardClass *pcc;
|
||||
|
||||
if (s->slot.attached) {
|
||||
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
||||
return pcc->attr_read(s->card, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
PCMCIACardClass *pcc;
|
||||
|
||||
if (s->slot.attached) {
|
||||
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
||||
pcc->attr_write(s->card, offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
|
||||
hwaddr offset, unsigned size)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
PCMCIACardClass *pcc;
|
||||
|
||||
if (s->slot.attached) {
|
||||
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
||||
return pcc->io_read(s->card, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
PCMCIACardClass *pcc;
|
||||
|
||||
if (s->slot.attached) {
|
||||
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
||||
pcc->io_write(s->card, offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
|
||||
.read = pxa2xx_pcmcia_common_read,
|
||||
.write = pxa2xx_pcmcia_common_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN
|
||||
};
|
||||
|
||||
static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
|
||||
.read = pxa2xx_pcmcia_attr_read,
|
||||
.write = pxa2xx_pcmcia_attr_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN
|
||||
};
|
||||
|
||||
static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
|
||||
.read = pxa2xx_pcmcia_io_read,
|
||||
.write = pxa2xx_pcmcia_io_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN
|
||||
};
|
||||
|
||||
static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
if (!s->irq)
|
||||
return;
|
||||
|
||||
qemu_set_irq(s->irq, level);
|
||||
}
|
||||
|
||||
static void pxa2xx_pcmcia_initfn(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(obj);
|
||||
|
||||
memory_region_init(&s->container_mem, obj, "container", 0x10000000);
|
||||
sysbus_init_mmio(sbd, &s->container_mem);
|
||||
|
||||
/* Socket I/O Memory Space */
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_pcmcia_io_ops, s,
|
||||
"pxa2xx-pcmcia-io", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x00000000,
|
||||
&s->iomem);
|
||||
|
||||
/* Then next 64 MB is reserved */
|
||||
|
||||
/* Socket Attribute Memory Space */
|
||||
memory_region_init_io(&s->attr_iomem, obj, &pxa2xx_pcmcia_attr_ops, s,
|
||||
"pxa2xx-pcmcia-attribute", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x08000000,
|
||||
&s->attr_iomem);
|
||||
|
||||
/* Socket Common Memory Space */
|
||||
memory_region_init_io(&s->common_iomem, obj, &pxa2xx_pcmcia_common_ops, s,
|
||||
"pxa2xx-pcmcia-common", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x0c000000,
|
||||
&s->common_iomem);
|
||||
|
||||
s->slot.irq = qemu_allocate_irq(pxa2xx_pcmcia_set_irq, s, 0);
|
||||
|
||||
object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
|
||||
(Object **)&s->card,
|
||||
NULL, /* read-only property */
|
||||
0);
|
||||
}
|
||||
|
||||
/* Insert a new card into a slot */
|
||||
int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
PCMCIACardClass *pcc;
|
||||
|
||||
if (s->slot.attached) {
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (s->cd_irq) {
|
||||
qemu_irq_raise(s->cd_irq);
|
||||
}
|
||||
|
||||
s->card = card;
|
||||
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
||||
|
||||
s->slot.attached = true;
|
||||
s->card->slot = &s->slot;
|
||||
pcc->attach(s->card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Eject card from the slot */
|
||||
int pxa2xx_pcmcia_detach(void *opaque)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
PCMCIACardClass *pcc;
|
||||
|
||||
if (!s->slot.attached) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
||||
pcc->detach(s->card);
|
||||
s->card->slot = NULL;
|
||||
s->card = NULL;
|
||||
|
||||
s->slot.attached = false;
|
||||
|
||||
if (s->irq) {
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
if (s->cd_irq) {
|
||||
qemu_irq_lower(s->cd_irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Who to notify on card events */
|
||||
void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
|
||||
{
|
||||
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
||||
s->irq = irq;
|
||||
s->cd_irq = cd_irq;
|
||||
}
|
||||
|
||||
static const TypeInfo pxa2xx_pcmcia_type_info = {
|
||||
.name = TYPE_PXA2XX_PCMCIA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PXA2xxPCMCIAState),
|
||||
.instance_init = pxa2xx_pcmcia_initfn,
|
||||
};
|
||||
|
||||
static void pxa2xx_pcmcia_register_types(void)
|
||||
{
|
||||
type_register_static(&pxa2xx_pcmcia_type_info);
|
||||
}
|
||||
|
||||
type_init(pxa2xx_pcmcia_register_types)
|
|
@ -14,10 +14,6 @@ config M48T59
|
|||
config PL031
|
||||
bool
|
||||
|
||||
config TWL92230
|
||||
bool
|
||||
depends on I2C
|
||||
|
||||
config MC146818RTC
|
||||
depends on ISA_BUS
|
||||
bool
|
||||
|
|
|
@ -3,7 +3,6 @@ system_ss.add(when: 'CONFIG_DS1338', if_true: files('ds1338.c'))
|
|||
system_ss.add(when: 'CONFIG_M41T80', if_true: files('m41t80.c'))
|
||||
system_ss.add(when: 'CONFIG_M48T59', if_true: files('m48t59.c'))
|
||||
system_ss.add(when: 'CONFIG_PL031', if_true: files('pl031.c'))
|
||||
system_ss.add(when: 'CONFIG_TWL92230', if_true: files('twl92230.c'))
|
||||
system_ss.add(when: ['CONFIG_ISA_BUS', 'CONFIG_M48T59'], if_true: files('m48t59-isa.c'))
|
||||
system_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-rtc.c'))
|
||||
|
||||
|
|
|
@ -1,882 +0,0 @@
|
|||
/*
|
||||
* TI TWL92230C energy-management companion device for the OMAP24xx.
|
||||
* Aka. Menelaus (N4200 MENELAUS1_V2.2)
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/qemu-file-types.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/rtc.h"
|
||||
#include "qemu/bcd.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define VERBOSE 1
|
||||
|
||||
#define TYPE_TWL92230 "twl92230"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MenelausState, TWL92230)
|
||||
|
||||
struct MenelausState {
|
||||
I2CSlave parent_obj;
|
||||
|
||||
int firstbyte;
|
||||
uint8_t reg;
|
||||
|
||||
uint8_t vcore[5];
|
||||
uint8_t dcdc[3];
|
||||
uint8_t ldo[8];
|
||||
uint8_t sleep[2];
|
||||
uint8_t osc;
|
||||
uint8_t detect;
|
||||
uint16_t mask;
|
||||
uint16_t status;
|
||||
uint8_t dir;
|
||||
uint8_t inputs;
|
||||
uint8_t outputs;
|
||||
uint8_t bbsms;
|
||||
uint8_t pull[4];
|
||||
uint8_t mmc_ctrl[3];
|
||||
uint8_t mmc_debounce;
|
||||
struct {
|
||||
uint8_t ctrl;
|
||||
uint16_t comp;
|
||||
QEMUTimer *hz_tm;
|
||||
int64_t next;
|
||||
struct tm tm;
|
||||
struct tm new;
|
||||
struct tm alm;
|
||||
int64_t sec_offset;
|
||||
int64_t alm_sec;
|
||||
int next_comp;
|
||||
} rtc;
|
||||
uint16_t rtc_next_vmstate;
|
||||
qemu_irq out[4];
|
||||
uint8_t pwrbtn_state;
|
||||
};
|
||||
|
||||
static inline void menelaus_update(MenelausState *s)
|
||||
{
|
||||
qemu_set_irq(s->out[3], s->status & ~s->mask);
|
||||
}
|
||||
|
||||
static inline void menelaus_rtc_start(MenelausState *s)
|
||||
{
|
||||
s->rtc.next += qemu_clock_get_ms(rtc_clock);
|
||||
timer_mod(s->rtc.hz_tm, s->rtc.next);
|
||||
}
|
||||
|
||||
static inline void menelaus_rtc_stop(MenelausState *s)
|
||||
{
|
||||
timer_del(s->rtc.hz_tm);
|
||||
s->rtc.next -= qemu_clock_get_ms(rtc_clock);
|
||||
if (s->rtc.next < 1)
|
||||
s->rtc.next = 1;
|
||||
}
|
||||
|
||||
static void menelaus_rtc_update(MenelausState *s)
|
||||
{
|
||||
qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset);
|
||||
}
|
||||
|
||||
static void menelaus_alm_update(MenelausState *s)
|
||||
{
|
||||
if ((s->rtc.ctrl & 3) == 3)
|
||||
s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset;
|
||||
}
|
||||
|
||||
static void menelaus_rtc_hz(void *opaque)
|
||||
{
|
||||
MenelausState *s = (MenelausState *) opaque;
|
||||
|
||||
s->rtc.next_comp --;
|
||||
s->rtc.alm_sec --;
|
||||
s->rtc.next += 1000;
|
||||
timer_mod(s->rtc.hz_tm, s->rtc.next);
|
||||
if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */
|
||||
menelaus_rtc_update(s);
|
||||
if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec)
|
||||
s->status |= 1 << 8; /* RTCTMR */
|
||||
else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min)
|
||||
s->status |= 1 << 8; /* RTCTMR */
|
||||
else if (!s->rtc.tm.tm_hour)
|
||||
s->status |= 1 << 8; /* RTCTMR */
|
||||
} else
|
||||
s->status |= 1 << 8; /* RTCTMR */
|
||||
if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */
|
||||
if (s->rtc.alm_sec == 0)
|
||||
s->status |= 1 << 9; /* RTCALM */
|
||||
/* TODO: wake-up */
|
||||
}
|
||||
if (s->rtc.next_comp <= 0) {
|
||||
s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000);
|
||||
s->rtc.next_comp = 3600;
|
||||
}
|
||||
menelaus_update(s);
|
||||
}
|
||||
|
||||
static void menelaus_reset(I2CSlave *i2c)
|
||||
{
|
||||
MenelausState *s = TWL92230(i2c);
|
||||
|
||||
s->reg = 0x00;
|
||||
|
||||
s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */
|
||||
s->vcore[1] = 0x05;
|
||||
s->vcore[2] = 0x02;
|
||||
s->vcore[3] = 0x0c;
|
||||
s->vcore[4] = 0x03;
|
||||
s->dcdc[0] = 0x33; /* Depends on wiring */
|
||||
s->dcdc[1] = 0x03;
|
||||
s->dcdc[2] = 0x00;
|
||||
s->ldo[0] = 0x95;
|
||||
s->ldo[1] = 0x7e;
|
||||
s->ldo[2] = 0x00;
|
||||
s->ldo[3] = 0x00; /* Depends on wiring */
|
||||
s->ldo[4] = 0x03; /* Depends on wiring */
|
||||
s->ldo[5] = 0x00;
|
||||
s->ldo[6] = 0x00;
|
||||
s->ldo[7] = 0x00;
|
||||
s->sleep[0] = 0x00;
|
||||
s->sleep[1] = 0x00;
|
||||
s->osc = 0x01;
|
||||
s->detect = 0x09;
|
||||
s->mask = 0x0fff;
|
||||
s->status = 0;
|
||||
s->dir = 0x07;
|
||||
s->outputs = 0x00;
|
||||
s->bbsms = 0x00;
|
||||
s->pull[0] = 0x00;
|
||||
s->pull[1] = 0x00;
|
||||
s->pull[2] = 0x00;
|
||||
s->pull[3] = 0x00;
|
||||
s->mmc_ctrl[0] = 0x03;
|
||||
s->mmc_ctrl[1] = 0xc0;
|
||||
s->mmc_ctrl[2] = 0x00;
|
||||
s->mmc_debounce = 0x05;
|
||||
|
||||
if (s->rtc.ctrl & 1)
|
||||
menelaus_rtc_stop(s);
|
||||
s->rtc.ctrl = 0x00;
|
||||
s->rtc.comp = 0x0000;
|
||||
s->rtc.next = 1000;
|
||||
s->rtc.sec_offset = 0;
|
||||
s->rtc.next_comp = 1800;
|
||||
s->rtc.alm_sec = 1800;
|
||||
s->rtc.alm.tm_sec = 0x00;
|
||||
s->rtc.alm.tm_min = 0x00;
|
||||
s->rtc.alm.tm_hour = 0x00;
|
||||
s->rtc.alm.tm_mday = 0x01;
|
||||
s->rtc.alm.tm_mon = 0x00;
|
||||
s->rtc.alm.tm_year = 2004;
|
||||
menelaus_update(s);
|
||||
}
|
||||
|
||||
static void menelaus_gpio_set(void *opaque, int line, int level)
|
||||
{
|
||||
MenelausState *s = (MenelausState *) opaque;
|
||||
|
||||
if (line < 3) {
|
||||
/* No interrupt generated */
|
||||
s->inputs &= ~(1 << line);
|
||||
s->inputs |= level << line;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->pwrbtn_state && level) {
|
||||
s->status |= 1 << 11; /* PSHBTN */
|
||||
menelaus_update(s);
|
||||
}
|
||||
s->pwrbtn_state = level;
|
||||
}
|
||||
|
||||
#define MENELAUS_REV 0x01
|
||||
#define MENELAUS_VCORE_CTRL1 0x02
|
||||
#define MENELAUS_VCORE_CTRL2 0x03
|
||||
#define MENELAUS_VCORE_CTRL3 0x04
|
||||
#define MENELAUS_VCORE_CTRL4 0x05
|
||||
#define MENELAUS_VCORE_CTRL5 0x06
|
||||
#define MENELAUS_DCDC_CTRL1 0x07
|
||||
#define MENELAUS_DCDC_CTRL2 0x08
|
||||
#define MENELAUS_DCDC_CTRL3 0x09
|
||||
#define MENELAUS_LDO_CTRL1 0x0a
|
||||
#define MENELAUS_LDO_CTRL2 0x0b
|
||||
#define MENELAUS_LDO_CTRL3 0x0c
|
||||
#define MENELAUS_LDO_CTRL4 0x0d
|
||||
#define MENELAUS_LDO_CTRL5 0x0e
|
||||
#define MENELAUS_LDO_CTRL6 0x0f
|
||||
#define MENELAUS_LDO_CTRL7 0x10
|
||||
#define MENELAUS_LDO_CTRL8 0x11
|
||||
#define MENELAUS_SLEEP_CTRL1 0x12
|
||||
#define MENELAUS_SLEEP_CTRL2 0x13
|
||||
#define MENELAUS_DEVICE_OFF 0x14
|
||||
#define MENELAUS_OSC_CTRL 0x15
|
||||
#define MENELAUS_DETECT_CTRL 0x16
|
||||
#define MENELAUS_INT_MASK1 0x17
|
||||
#define MENELAUS_INT_MASK2 0x18
|
||||
#define MENELAUS_INT_STATUS1 0x19
|
||||
#define MENELAUS_INT_STATUS2 0x1a
|
||||
#define MENELAUS_INT_ACK1 0x1b
|
||||
#define MENELAUS_INT_ACK2 0x1c
|
||||
#define MENELAUS_GPIO_CTRL 0x1d
|
||||
#define MENELAUS_GPIO_IN 0x1e
|
||||
#define MENELAUS_GPIO_OUT 0x1f
|
||||
#define MENELAUS_BBSMS 0x20
|
||||
#define MENELAUS_RTC_CTRL 0x21
|
||||
#define MENELAUS_RTC_UPDATE 0x22
|
||||
#define MENELAUS_RTC_SEC 0x23
|
||||
#define MENELAUS_RTC_MIN 0x24
|
||||
#define MENELAUS_RTC_HR 0x25
|
||||
#define MENELAUS_RTC_DAY 0x26
|
||||
#define MENELAUS_RTC_MON 0x27
|
||||
#define MENELAUS_RTC_YR 0x28
|
||||
#define MENELAUS_RTC_WKDAY 0x29
|
||||
#define MENELAUS_RTC_AL_SEC 0x2a
|
||||
#define MENELAUS_RTC_AL_MIN 0x2b
|
||||
#define MENELAUS_RTC_AL_HR 0x2c
|
||||
#define MENELAUS_RTC_AL_DAY 0x2d
|
||||
#define MENELAUS_RTC_AL_MON 0x2e
|
||||
#define MENELAUS_RTC_AL_YR 0x2f
|
||||
#define MENELAUS_RTC_COMP_MSB 0x30
|
||||
#define MENELAUS_RTC_COMP_LSB 0x31
|
||||
#define MENELAUS_S1_PULL_EN 0x32
|
||||
#define MENELAUS_S1_PULL_DIR 0x33
|
||||
#define MENELAUS_S2_PULL_EN 0x34
|
||||
#define MENELAUS_S2_PULL_DIR 0x35
|
||||
#define MENELAUS_MCT_CTRL1 0x36
|
||||
#define MENELAUS_MCT_CTRL2 0x37
|
||||
#define MENELAUS_MCT_CTRL3 0x38
|
||||
#define MENELAUS_MCT_PIN_ST 0x39
|
||||
#define MENELAUS_DEBOUNCE1 0x3a
|
||||
|
||||
static uint8_t menelaus_read(void *opaque, uint8_t addr)
|
||||
{
|
||||
MenelausState *s = (MenelausState *) opaque;
|
||||
|
||||
switch (addr) {
|
||||
case MENELAUS_REV:
|
||||
return 0x22;
|
||||
|
||||
case MENELAUS_VCORE_CTRL1 ... MENELAUS_VCORE_CTRL5:
|
||||
return s->vcore[addr - MENELAUS_VCORE_CTRL1];
|
||||
|
||||
case MENELAUS_DCDC_CTRL1 ... MENELAUS_DCDC_CTRL3:
|
||||
return s->dcdc[addr - MENELAUS_DCDC_CTRL1];
|
||||
|
||||
case MENELAUS_LDO_CTRL1 ... MENELAUS_LDO_CTRL8:
|
||||
return s->ldo[addr - MENELAUS_LDO_CTRL1];
|
||||
|
||||
case MENELAUS_SLEEP_CTRL1:
|
||||
case MENELAUS_SLEEP_CTRL2:
|
||||
return s->sleep[addr - MENELAUS_SLEEP_CTRL1];
|
||||
|
||||
case MENELAUS_DEVICE_OFF:
|
||||
return 0;
|
||||
|
||||
case MENELAUS_OSC_CTRL:
|
||||
return s->osc | (1 << 7); /* CLK32K_GOOD */
|
||||
|
||||
case MENELAUS_DETECT_CTRL:
|
||||
return s->detect;
|
||||
|
||||
case MENELAUS_INT_MASK1:
|
||||
return (s->mask >> 0) & 0xff;
|
||||
case MENELAUS_INT_MASK2:
|
||||
return (s->mask >> 8) & 0xff;
|
||||
|
||||
case MENELAUS_INT_STATUS1:
|
||||
return (s->status >> 0) & 0xff;
|
||||
case MENELAUS_INT_STATUS2:
|
||||
return (s->status >> 8) & 0xff;
|
||||
|
||||
case MENELAUS_INT_ACK1:
|
||||
case MENELAUS_INT_ACK2:
|
||||
return 0;
|
||||
|
||||
case MENELAUS_GPIO_CTRL:
|
||||
return s->dir;
|
||||
case MENELAUS_GPIO_IN:
|
||||
return s->inputs | (~s->dir & s->outputs);
|
||||
case MENELAUS_GPIO_OUT:
|
||||
return s->outputs;
|
||||
|
||||
case MENELAUS_BBSMS:
|
||||
return s->bbsms;
|
||||
|
||||
case MENELAUS_RTC_CTRL:
|
||||
return s->rtc.ctrl;
|
||||
case MENELAUS_RTC_UPDATE:
|
||||
return 0x00;
|
||||
case MENELAUS_RTC_SEC:
|
||||
menelaus_rtc_update(s);
|
||||
return to_bcd(s->rtc.tm.tm_sec);
|
||||
case MENELAUS_RTC_MIN:
|
||||
menelaus_rtc_update(s);
|
||||
return to_bcd(s->rtc.tm.tm_min);
|
||||
case MENELAUS_RTC_HR:
|
||||
menelaus_rtc_update(s);
|
||||
if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
|
||||
return to_bcd((s->rtc.tm.tm_hour % 12) + 1) |
|
||||
(!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */
|
||||
else
|
||||
return to_bcd(s->rtc.tm.tm_hour);
|
||||
case MENELAUS_RTC_DAY:
|
||||
menelaus_rtc_update(s);
|
||||
return to_bcd(s->rtc.tm.tm_mday);
|
||||
case MENELAUS_RTC_MON:
|
||||
menelaus_rtc_update(s);
|
||||
return to_bcd(s->rtc.tm.tm_mon + 1);
|
||||
case MENELAUS_RTC_YR:
|
||||
menelaus_rtc_update(s);
|
||||
return to_bcd(s->rtc.tm.tm_year - 2000);
|
||||
case MENELAUS_RTC_WKDAY:
|
||||
menelaus_rtc_update(s);
|
||||
return to_bcd(s->rtc.tm.tm_wday);
|
||||
case MENELAUS_RTC_AL_SEC:
|
||||
return to_bcd(s->rtc.alm.tm_sec);
|
||||
case MENELAUS_RTC_AL_MIN:
|
||||
return to_bcd(s->rtc.alm.tm_min);
|
||||
case MENELAUS_RTC_AL_HR:
|
||||
if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
|
||||
return to_bcd((s->rtc.alm.tm_hour % 12) + 1) |
|
||||
(!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */
|
||||
else
|
||||
return to_bcd(s->rtc.alm.tm_hour);
|
||||
case MENELAUS_RTC_AL_DAY:
|
||||
return to_bcd(s->rtc.alm.tm_mday);
|
||||
case MENELAUS_RTC_AL_MON:
|
||||
return to_bcd(s->rtc.alm.tm_mon + 1);
|
||||
case MENELAUS_RTC_AL_YR:
|
||||
return to_bcd(s->rtc.alm.tm_year - 2000);
|
||||
case MENELAUS_RTC_COMP_MSB:
|
||||
return (s->rtc.comp >> 8) & 0xff;
|
||||
case MENELAUS_RTC_COMP_LSB:
|
||||
return (s->rtc.comp >> 0) & 0xff;
|
||||
|
||||
case MENELAUS_S1_PULL_EN:
|
||||
return s->pull[0];
|
||||
case MENELAUS_S1_PULL_DIR:
|
||||
return s->pull[1];
|
||||
case MENELAUS_S2_PULL_EN:
|
||||
return s->pull[2];
|
||||
case MENELAUS_S2_PULL_DIR:
|
||||
return s->pull[3];
|
||||
|
||||
case MENELAUS_MCT_CTRL1 ... MENELAUS_MCT_CTRL3:
|
||||
return s->mmc_ctrl[addr - MENELAUS_MCT_CTRL1];
|
||||
case MENELAUS_MCT_PIN_ST:
|
||||
/* TODO: return the real Card Detect */
|
||||
return 0;
|
||||
case MENELAUS_DEBOUNCE1:
|
||||
return s->mmc_debounce;
|
||||
|
||||
default:
|
||||
#ifdef VERBOSE
|
||||
printf("%s: unknown register %02x\n", __func__, addr);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
|
||||
{
|
||||
MenelausState *s = (MenelausState *) opaque;
|
||||
int line;
|
||||
struct tm tm;
|
||||
|
||||
switch (addr) {
|
||||
case MENELAUS_VCORE_CTRL1:
|
||||
s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
|
||||
break;
|
||||
case MENELAUS_VCORE_CTRL2:
|
||||
s->vcore[1] = value;
|
||||
break;
|
||||
case MENELAUS_VCORE_CTRL3:
|
||||
s->vcore[2] = MIN(value & 0x1f, 0x12);
|
||||
break;
|
||||
case MENELAUS_VCORE_CTRL4:
|
||||
s->vcore[3] = MIN(value & 0x1f, 0x12);
|
||||
break;
|
||||
case MENELAUS_VCORE_CTRL5:
|
||||
s->vcore[4] = value & 3;
|
||||
/* XXX
|
||||
* auto set to 3 on M_Active, nRESWARM
|
||||
* auto set to 0 on M_WaitOn, M_Backup
|
||||
*/
|
||||
break;
|
||||
|
||||
case MENELAUS_DCDC_CTRL1:
|
||||
s->dcdc[0] = value & 0x3f;
|
||||
break;
|
||||
case MENELAUS_DCDC_CTRL2:
|
||||
s->dcdc[1] = value & 0x07;
|
||||
/* XXX
|
||||
* auto set to 3 on M_Active, nRESWARM
|
||||
* auto set to 0 on M_WaitOn, M_Backup
|
||||
*/
|
||||
break;
|
||||
case MENELAUS_DCDC_CTRL3:
|
||||
s->dcdc[2] = value & 0x07;
|
||||
break;
|
||||
|
||||
case MENELAUS_LDO_CTRL1:
|
||||
s->ldo[0] = value;
|
||||
break;
|
||||
case MENELAUS_LDO_CTRL2:
|
||||
s->ldo[1] = value & 0x7f;
|
||||
/* XXX
|
||||
* auto set to 0x7e on M_WaitOn, M_Backup
|
||||
*/
|
||||
break;
|
||||
case MENELAUS_LDO_CTRL3:
|
||||
s->ldo[2] = value & 3;
|
||||
/* XXX
|
||||
* auto set to 3 on M_Active, nRESWARM
|
||||
* auto set to 0 on M_WaitOn, M_Backup
|
||||
*/
|
||||
break;
|
||||
case MENELAUS_LDO_CTRL4:
|
||||
s->ldo[3] = value & 3;
|
||||
/* XXX
|
||||
* auto set to 3 on M_Active, nRESWARM
|
||||
* auto set to 0 on M_WaitOn, M_Backup
|
||||
*/
|
||||
break;
|
||||
case MENELAUS_LDO_CTRL5:
|
||||
s->ldo[4] = value & 3;
|
||||
/* XXX
|
||||
* auto set to 3 on M_Active, nRESWARM
|
||||
* auto set to 0 on M_WaitOn, M_Backup
|
||||
*/
|
||||
break;
|
||||
case MENELAUS_LDO_CTRL6:
|
||||
s->ldo[5] = value & 3;
|
||||
break;
|
||||
case MENELAUS_LDO_CTRL7:
|
||||
s->ldo[6] = value & 3;
|
||||
break;
|
||||
case MENELAUS_LDO_CTRL8:
|
||||
s->ldo[7] = value & 3;
|
||||
break;
|
||||
|
||||
case MENELAUS_SLEEP_CTRL1:
|
||||
case MENELAUS_SLEEP_CTRL2:
|
||||
s->sleep[addr - MENELAUS_SLEEP_CTRL1] = value;
|
||||
break;
|
||||
|
||||
case MENELAUS_DEVICE_OFF:
|
||||
if (value & 1) {
|
||||
menelaus_reset(I2C_SLAVE(s));
|
||||
}
|
||||
break;
|
||||
|
||||
case MENELAUS_OSC_CTRL:
|
||||
s->osc = value & 7;
|
||||
break;
|
||||
|
||||
case MENELAUS_DETECT_CTRL:
|
||||
s->detect = value & 0x7f;
|
||||
break;
|
||||
|
||||
case MENELAUS_INT_MASK1:
|
||||
s->mask &= 0xf00;
|
||||
s->mask |= value << 0;
|
||||
menelaus_update(s);
|
||||
break;
|
||||
case MENELAUS_INT_MASK2:
|
||||
s->mask &= 0x0ff;
|
||||
s->mask |= value << 8;
|
||||
menelaus_update(s);
|
||||
break;
|
||||
|
||||
case MENELAUS_INT_ACK1:
|
||||
s->status &= ~(((uint16_t) value) << 0);
|
||||
menelaus_update(s);
|
||||
break;
|
||||
case MENELAUS_INT_ACK2:
|
||||
s->status &= ~(((uint16_t) value) << 8);
|
||||
menelaus_update(s);
|
||||
break;
|
||||
|
||||
case MENELAUS_GPIO_CTRL:
|
||||
for (line = 0; line < 3; line ++) {
|
||||
if (((s->dir ^ value) >> line) & 1) {
|
||||
qemu_set_irq(s->out[line],
|
||||
((s->outputs & ~s->dir) >> line) & 1);
|
||||
}
|
||||
}
|
||||
s->dir = value & 0x67;
|
||||
break;
|
||||
case MENELAUS_GPIO_OUT:
|
||||
for (line = 0; line < 3; line ++) {
|
||||
if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) {
|
||||
qemu_set_irq(s->out[line], (s->outputs >> line) & 1);
|
||||
}
|
||||
}
|
||||
s->outputs = value & 0x07;
|
||||
break;
|
||||
|
||||
case MENELAUS_BBSMS:
|
||||
s->bbsms = 0x0d;
|
||||
break;
|
||||
|
||||
case MENELAUS_RTC_CTRL:
|
||||
if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */
|
||||
if (value & 1)
|
||||
menelaus_rtc_start(s);
|
||||
else
|
||||
menelaus_rtc_stop(s);
|
||||
}
|
||||
s->rtc.ctrl = value & 0x1f;
|
||||
menelaus_alm_update(s);
|
||||
break;
|
||||
case MENELAUS_RTC_UPDATE:
|
||||
menelaus_rtc_update(s);
|
||||
memcpy(&tm, &s->rtc.tm, sizeof(tm));
|
||||
switch (value & 0xf) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
tm.tm_sec = s->rtc.new.tm_sec;
|
||||
break;
|
||||
case 2:
|
||||
tm.tm_min = s->rtc.new.tm_min;
|
||||
break;
|
||||
case 3:
|
||||
if (s->rtc.new.tm_hour > 23)
|
||||
goto rtc_badness;
|
||||
tm.tm_hour = s->rtc.new.tm_hour;
|
||||
break;
|
||||
case 4:
|
||||
if (s->rtc.new.tm_mday < 1)
|
||||
goto rtc_badness;
|
||||
/* TODO check range */
|
||||
tm.tm_mday = s->rtc.new.tm_mday;
|
||||
break;
|
||||
case 5:
|
||||
if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
|
||||
goto rtc_badness;
|
||||
tm.tm_mon = s->rtc.new.tm_mon;
|
||||
break;
|
||||
case 6:
|
||||
tm.tm_year = s->rtc.new.tm_year;
|
||||
break;
|
||||
case 7:
|
||||
/* TODO set .tm_mday instead */
|
||||
tm.tm_wday = s->rtc.new.tm_wday;
|
||||
break;
|
||||
case 8:
|
||||
if (s->rtc.new.tm_hour > 23)
|
||||
goto rtc_badness;
|
||||
if (s->rtc.new.tm_mday < 1)
|
||||
goto rtc_badness;
|
||||
if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
|
||||
goto rtc_badness;
|
||||
tm.tm_sec = s->rtc.new.tm_sec;
|
||||
tm.tm_min = s->rtc.new.tm_min;
|
||||
tm.tm_hour = s->rtc.new.tm_hour;
|
||||
tm.tm_mday = s->rtc.new.tm_mday;
|
||||
tm.tm_mon = s->rtc.new.tm_mon;
|
||||
tm.tm_year = s->rtc.new.tm_year;
|
||||
break;
|
||||
rtc_badness:
|
||||
default:
|
||||
fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
|
||||
__func__, value);
|
||||
s->status |= 1 << 10; /* RTCERR */
|
||||
menelaus_update(s);
|
||||
}
|
||||
s->rtc.sec_offset = qemu_timedate_diff(&tm);
|
||||
break;
|
||||
case MENELAUS_RTC_SEC:
|
||||
s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
|
||||
break;
|
||||
case MENELAUS_RTC_MIN:
|
||||
s->rtc.tm.tm_min = from_bcd(value & 0x7f);
|
||||
break;
|
||||
case MENELAUS_RTC_HR:
|
||||
s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
|
||||
MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
|
||||
from_bcd(value & 0x3f);
|
||||
break;
|
||||
case MENELAUS_RTC_DAY:
|
||||
s->rtc.tm.tm_mday = from_bcd(value);
|
||||
break;
|
||||
case MENELAUS_RTC_MON:
|
||||
s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
|
||||
break;
|
||||
case MENELAUS_RTC_YR:
|
||||
s->rtc.tm.tm_year = 2000 + from_bcd(value);
|
||||
break;
|
||||
case MENELAUS_RTC_WKDAY:
|
||||
s->rtc.tm.tm_mday = from_bcd(value);
|
||||
break;
|
||||
case MENELAUS_RTC_AL_SEC:
|
||||
s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
|
||||
menelaus_alm_update(s);
|
||||
break;
|
||||
case MENELAUS_RTC_AL_MIN:
|
||||
s->rtc.alm.tm_min = from_bcd(value & 0x7f);
|
||||
menelaus_alm_update(s);
|
||||
break;
|
||||
case MENELAUS_RTC_AL_HR:
|
||||
s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
|
||||
MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
|
||||
from_bcd(value & 0x3f);
|
||||
menelaus_alm_update(s);
|
||||
break;
|
||||
case MENELAUS_RTC_AL_DAY:
|
||||
s->rtc.alm.tm_mday = from_bcd(value);
|
||||
menelaus_alm_update(s);
|
||||
break;
|
||||
case MENELAUS_RTC_AL_MON:
|
||||
s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
|
||||
menelaus_alm_update(s);
|
||||
break;
|
||||
case MENELAUS_RTC_AL_YR:
|
||||
s->rtc.alm.tm_year = 2000 + from_bcd(value);
|
||||
menelaus_alm_update(s);
|
||||
break;
|
||||
case MENELAUS_RTC_COMP_MSB:
|
||||
s->rtc.comp &= 0xff;
|
||||
s->rtc.comp |= value << 8;
|
||||
break;
|
||||
case MENELAUS_RTC_COMP_LSB:
|
||||
s->rtc.comp &= 0xff << 8;
|
||||
s->rtc.comp |= value;
|
||||
break;
|
||||
|
||||
case MENELAUS_S1_PULL_EN:
|
||||
s->pull[0] = value;
|
||||
break;
|
||||
case MENELAUS_S1_PULL_DIR:
|
||||
s->pull[1] = value & 0x1f;
|
||||
break;
|
||||
case MENELAUS_S2_PULL_EN:
|
||||
s->pull[2] = value;
|
||||
break;
|
||||
case MENELAUS_S2_PULL_DIR:
|
||||
s->pull[3] = value & 0x1f;
|
||||
break;
|
||||
|
||||
case MENELAUS_MCT_CTRL1:
|
||||
s->mmc_ctrl[0] = value & 0x7f;
|
||||
break;
|
||||
case MENELAUS_MCT_CTRL2:
|
||||
s->mmc_ctrl[1] = value;
|
||||
/* TODO update Card Detect interrupts */
|
||||
break;
|
||||
case MENELAUS_MCT_CTRL3:
|
||||
s->mmc_ctrl[2] = value & 0xf;
|
||||
break;
|
||||
case MENELAUS_DEBOUNCE1:
|
||||
s->mmc_debounce = value & 0x3f;
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef VERBOSE
|
||||
printf("%s: unknown register %02x\n", __func__, addr);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int menelaus_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
MenelausState *s = TWL92230(i2c);
|
||||
|
||||
if (event == I2C_START_SEND)
|
||||
s->firstbyte = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int menelaus_tx(I2CSlave *i2c, uint8_t data)
|
||||
{
|
||||
MenelausState *s = TWL92230(i2c);
|
||||
|
||||
/* Interpret register address byte */
|
||||
if (s->firstbyte) {
|
||||
s->reg = data;
|
||||
s->firstbyte = 0;
|
||||
} else
|
||||
menelaus_write(s, s->reg ++, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t menelaus_rx(I2CSlave *i2c)
|
||||
{
|
||||
MenelausState *s = TWL92230(i2c);
|
||||
|
||||
return menelaus_read(s, s->reg ++);
|
||||
}
|
||||
|
||||
/* Save restore 32 bit int as uint16_t
|
||||
This is a Big hack, but it is how the old state did it.
|
||||
Or we broke compatibility in the state, or we can't use struct tm
|
||||
*/
|
||||
|
||||
static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size,
|
||||
const VMStateField *field)
|
||||
{
|
||||
int *v = pv;
|
||||
*v = qemu_get_be16(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int put_int32_as_uint16(QEMUFile *f, void *pv, size_t size,
|
||||
const VMStateField *field, JSONWriter *vmdesc)
|
||||
{
|
||||
int *v = pv;
|
||||
qemu_put_be16(f, *v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateInfo vmstate_hack_int32_as_uint16 = {
|
||||
.name = "int32_as_uint16",
|
||||
.get = get_int32_as_uint16,
|
||||
.put = put_int32_as_uint16,
|
||||
};
|
||||
|
||||
#define VMSTATE_UINT16_HACK(_f, _s) \
|
||||
VMSTATE_SINGLE(_f, _s, 0, vmstate_hack_int32_as_uint16, int32_t)
|
||||
|
||||
|
||||
static const VMStateDescription vmstate_menelaus_tm = {
|
||||
.name = "menelaus_tm",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT16_HACK(tm_sec, struct tm),
|
||||
VMSTATE_UINT16_HACK(tm_min, struct tm),
|
||||
VMSTATE_UINT16_HACK(tm_hour, struct tm),
|
||||
VMSTATE_UINT16_HACK(tm_mday, struct tm),
|
||||
VMSTATE_UINT16_HACK(tm_min, struct tm),
|
||||
VMSTATE_UINT16_HACK(tm_year, struct tm),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static int menelaus_pre_save(void *opaque)
|
||||
{
|
||||
MenelausState *s = opaque;
|
||||
/* Should be <= 1000 */
|
||||
s->rtc_next_vmstate = s->rtc.next - qemu_clock_get_ms(rtc_clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int menelaus_post_load(void *opaque, int version_id)
|
||||
{
|
||||
MenelausState *s = opaque;
|
||||
|
||||
if (s->rtc.ctrl & 1) /* RTC_EN */
|
||||
menelaus_rtc_stop(s);
|
||||
|
||||
s->rtc.next = s->rtc_next_vmstate;
|
||||
|
||||
menelaus_alm_update(s);
|
||||
menelaus_update(s);
|
||||
if (s->rtc.ctrl & 1) /* RTC_EN */
|
||||
menelaus_rtc_start(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_menelaus = {
|
||||
.name = "menelaus",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.pre_save = menelaus_pre_save,
|
||||
.post_load = menelaus_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_INT32(firstbyte, MenelausState),
|
||||
VMSTATE_UINT8(reg, MenelausState),
|
||||
VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5),
|
||||
VMSTATE_UINT8_ARRAY(dcdc, MenelausState, 3),
|
||||
VMSTATE_UINT8_ARRAY(ldo, MenelausState, 8),
|
||||
VMSTATE_UINT8_ARRAY(sleep, MenelausState, 2),
|
||||
VMSTATE_UINT8(osc, MenelausState),
|
||||
VMSTATE_UINT8(detect, MenelausState),
|
||||
VMSTATE_UINT16(mask, MenelausState),
|
||||
VMSTATE_UINT16(status, MenelausState),
|
||||
VMSTATE_UINT8(dir, MenelausState),
|
||||
VMSTATE_UINT8(inputs, MenelausState),
|
||||
VMSTATE_UINT8(outputs, MenelausState),
|
||||
VMSTATE_UINT8(bbsms, MenelausState),
|
||||
VMSTATE_UINT8_ARRAY(pull, MenelausState, 4),
|
||||
VMSTATE_UINT8_ARRAY(mmc_ctrl, MenelausState, 3),
|
||||
VMSTATE_UINT8(mmc_debounce, MenelausState),
|
||||
VMSTATE_UINT8(rtc.ctrl, MenelausState),
|
||||
VMSTATE_UINT16(rtc.comp, MenelausState),
|
||||
VMSTATE_UINT16(rtc_next_vmstate, MenelausState),
|
||||
VMSTATE_STRUCT(rtc.new, MenelausState, 0, vmstate_menelaus_tm,
|
||||
struct tm),
|
||||
VMSTATE_STRUCT(rtc.alm, MenelausState, 0, vmstate_menelaus_tm,
|
||||
struct tm),
|
||||
VMSTATE_UINT8(pwrbtn_state, MenelausState),
|
||||
VMSTATE_I2C_SLAVE(parent_obj, MenelausState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void twl92230_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MenelausState *s = TWL92230(dev);
|
||||
|
||||
s->rtc.hz_tm = timer_new_ms(rtc_clock, menelaus_rtc_hz, s);
|
||||
/* Three output pins plus one interrupt pin. */
|
||||
qdev_init_gpio_out(dev, s->out, 4);
|
||||
|
||||
/* Three input pins plus one power-button pin. */
|
||||
qdev_init_gpio_in(dev, menelaus_gpio_set, 4);
|
||||
|
||||
menelaus_reset(I2C_SLAVE(dev));
|
||||
}
|
||||
|
||||
static void twl92230_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
dc->realize = twl92230_realize;
|
||||
sc->event = menelaus_event;
|
||||
sc->recv = menelaus_rx;
|
||||
sc->send = menelaus_tx;
|
||||
dc->vmsd = &vmstate_menelaus;
|
||||
}
|
||||
|
||||
static const TypeInfo twl92230_info = {
|
||||
.name = TYPE_TWL92230,
|
||||
.parent = TYPE_I2C_SLAVE,
|
||||
.instance_size = sizeof(MenelausState),
|
||||
.class_init = twl92230_class_init,
|
||||
};
|
||||
|
||||
static void twl92230_register_types(void)
|
||||
{
|
||||
type_register_static(&twl92230_info);
|
||||
}
|
||||
|
||||
type_init(twl92230_register_types)
|
|
@ -5,7 +5,6 @@ system_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c'))
|
|||
system_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c'))
|
||||
system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
|
||||
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
|
||||
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
|
||||
system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
|
||||
|
|
|
@ -573,24 +573,6 @@ static const MemoryRegionOps omap_mmc_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void omap_mmc_cover_cb(void *opaque, int line, int level)
|
||||
{
|
||||
struct omap_mmc_s *host = opaque;
|
||||
|
||||
if (!host->cdet_state && level) {
|
||||
host->status |= 0x0002;
|
||||
omap_mmc_interrupts_update(host);
|
||||
if (host->cdet_wakeup) {
|
||||
/* TODO: Assert wake-up */
|
||||
}
|
||||
}
|
||||
|
||||
if (host->cdet_state != level) {
|
||||
qemu_set_irq(host->coverswitch, level);
|
||||
host->cdet_state = level;
|
||||
}
|
||||
}
|
||||
|
||||
struct omap_mmc_s *omap_mmc_init(hwaddr base,
|
||||
MemoryRegion *sysmem,
|
||||
BlockBackend *blk,
|
||||
|
@ -617,48 +599,3 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base,
|
|||
|
||||
return s;
|
||||
}
|
||||
|
||||
struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
|
||||
BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
|
||||
omap_clk fclk, omap_clk iclk)
|
||||
{
|
||||
struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
|
||||
|
||||
s->irq = irq;
|
||||
s->dma = dma;
|
||||
s->clk = fclk;
|
||||
s->lines = 4;
|
||||
s->rev = 2;
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc",
|
||||
omap_l4_region_size(ta, 0));
|
||||
omap_l4_attach(ta, 0, &s->iomem);
|
||||
|
||||
/* Instantiate the storage */
|
||||
s->card = sd_init(blk, false);
|
||||
if (s->card == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0);
|
||||
sd_set_cb(s->card, NULL, s->cdet);
|
||||
|
||||
omap_mmc_reset(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
|
||||
{
|
||||
if (s->cdet) {
|
||||
sd_set_cb(s->card, ro, s->cdet);
|
||||
s->coverswitch = cover;
|
||||
qemu_set_irq(cover, s->cdet_state);
|
||||
} else
|
||||
sd_set_cb(s->card, ro, cover);
|
||||
}
|
||||
|
||||
void omap_mmc_enable(struct omap_mmc_s *s, int enable)
|
||||
{
|
||||
sd_enable(s->card, enable);
|
||||
}
|
||||
|
|
|
@ -1,594 +0,0 @@
|
|||
/*
|
||||
* Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GPLv2.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "hw/sd/sd.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "trace.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus"
|
||||
/* This is reusing the SDBus typedef from SD_BUS */
|
||||
DECLARE_INSTANCE_CHECKER(SDBus, PXA2XX_MMCI_BUS,
|
||||
TYPE_PXA2XX_MMCI_BUS)
|
||||
|
||||
struct PXA2xxMMCIState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
qemu_irq rx_dma;
|
||||
qemu_irq tx_dma;
|
||||
qemu_irq inserted;
|
||||
qemu_irq readonly;
|
||||
|
||||
BlockBackend *blk;
|
||||
SDBus sdbus;
|
||||
|
||||
uint32_t status;
|
||||
uint32_t clkrt;
|
||||
uint32_t spi;
|
||||
uint32_t cmdat;
|
||||
uint32_t resp_tout;
|
||||
uint32_t read_tout;
|
||||
int32_t blklen;
|
||||
int32_t numblk;
|
||||
uint32_t intmask;
|
||||
uint32_t intreq;
|
||||
int32_t cmd;
|
||||
uint32_t arg;
|
||||
|
||||
int32_t active;
|
||||
int32_t bytesleft;
|
||||
uint8_t tx_fifo[64];
|
||||
uint32_t tx_start;
|
||||
uint32_t tx_len;
|
||||
uint8_t rx_fifo[32];
|
||||
uint32_t rx_start;
|
||||
uint32_t rx_len;
|
||||
uint16_t resp_fifo[9];
|
||||
uint32_t resp_len;
|
||||
|
||||
int32_t cmdreq;
|
||||
};
|
||||
|
||||
static bool pxa2xx_mmci_vmstate_validate(void *opaque, int version_id)
|
||||
{
|
||||
PXA2xxMMCIState *s = opaque;
|
||||
|
||||
return s->tx_start < ARRAY_SIZE(s->tx_fifo)
|
||||
&& s->rx_start < ARRAY_SIZE(s->rx_fifo)
|
||||
&& s->tx_len <= ARRAY_SIZE(s->tx_fifo)
|
||||
&& s->rx_len <= ARRAY_SIZE(s->rx_fifo)
|
||||
&& s->resp_len <= ARRAY_SIZE(s->resp_fifo);
|
||||
}
|
||||
|
||||
|
||||
static const VMStateDescription vmstate_pxa2xx_mmci = {
|
||||
.name = "pxa2xx-mmci",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(status, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(clkrt, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(spi, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(cmdat, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(resp_tout, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(read_tout, PXA2xxMMCIState),
|
||||
VMSTATE_INT32(blklen, PXA2xxMMCIState),
|
||||
VMSTATE_INT32(numblk, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(intmask, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(intreq, PXA2xxMMCIState),
|
||||
VMSTATE_INT32(cmd, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(arg, PXA2xxMMCIState),
|
||||
VMSTATE_INT32(cmdreq, PXA2xxMMCIState),
|
||||
VMSTATE_INT32(active, PXA2xxMMCIState),
|
||||
VMSTATE_INT32(bytesleft, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(tx_start, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(tx_len, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(rx_start, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(rx_len, PXA2xxMMCIState),
|
||||
VMSTATE_UINT32(resp_len, PXA2xxMMCIState),
|
||||
VMSTATE_VALIDATE("fifo size incorrect", pxa2xx_mmci_vmstate_validate),
|
||||
VMSTATE_UINT8_ARRAY(tx_fifo, PXA2xxMMCIState, 64),
|
||||
VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxMMCIState, 32),
|
||||
VMSTATE_UINT16_ARRAY(resp_fifo, PXA2xxMMCIState, 9),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */
|
||||
#define MMC_STAT 0x04 /* MMC Status register */
|
||||
#define MMC_CLKRT 0x08 /* MMC Clock Rate register */
|
||||
#define MMC_SPI 0x0c /* MMC SPI Mode register */
|
||||
#define MMC_CMDAT 0x10 /* MMC Command/Data register */
|
||||
#define MMC_RESTO 0x14 /* MMC Response Time-Out register */
|
||||
#define MMC_RDTO 0x18 /* MMC Read Time-Out register */
|
||||
#define MMC_BLKLEN 0x1c /* MMC Block Length register */
|
||||
#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */
|
||||
#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */
|
||||
#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */
|
||||
#define MMC_I_REG 0x2c /* MMC Interrupt Request register */
|
||||
#define MMC_CMD 0x30 /* MMC Command register */
|
||||
#define MMC_ARGH 0x34 /* MMC Argument High register */
|
||||
#define MMC_ARGL 0x38 /* MMC Argument Low register */
|
||||
#define MMC_RES 0x3c /* MMC Response FIFO */
|
||||
#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */
|
||||
#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */
|
||||
#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */
|
||||
#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */
|
||||
|
||||
/* Bitfield masks */
|
||||
#define STRPCL_STOP_CLK (1 << 0)
|
||||
#define STRPCL_STRT_CLK (1 << 1)
|
||||
#define STAT_TOUT_RES (1 << 1)
|
||||
#define STAT_CLK_EN (1 << 8)
|
||||
#define STAT_DATA_DONE (1 << 11)
|
||||
#define STAT_PRG_DONE (1 << 12)
|
||||
#define STAT_END_CMDRES (1 << 13)
|
||||
#define SPI_SPI_MODE (1 << 0)
|
||||
#define CMDAT_RES_TYPE (3 << 0)
|
||||
#define CMDAT_DATA_EN (1 << 2)
|
||||
#define CMDAT_WR_RD (1 << 3)
|
||||
#define CMDAT_DMA_EN (1 << 7)
|
||||
#define CMDAT_STOP_TRAN (1 << 10)
|
||||
#define INT_DATA_DONE (1 << 0)
|
||||
#define INT_PRG_DONE (1 << 1)
|
||||
#define INT_END_CMD (1 << 2)
|
||||
#define INT_STOP_CMD (1 << 3)
|
||||
#define INT_CLK_OFF (1 << 4)
|
||||
#define INT_RXFIFO_REQ (1 << 5)
|
||||
#define INT_TXFIFO_REQ (1 << 6)
|
||||
#define INT_TINT (1 << 7)
|
||||
#define INT_DAT_ERR (1 << 8)
|
||||
#define INT_RES_ERR (1 << 9)
|
||||
#define INT_RD_STALLED (1 << 10)
|
||||
#define INT_SDIO_INT (1 << 11)
|
||||
#define INT_SDIO_SACK (1 << 12)
|
||||
#define PRTBUF_PRT_BUF (1 << 0)
|
||||
|
||||
/* Route internal interrupt lines to the global IC and DMA */
|
||||
static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
|
||||
{
|
||||
uint32_t mask = s->intmask;
|
||||
if (s->cmdat & CMDAT_DMA_EN) {
|
||||
mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
|
||||
|
||||
qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
|
||||
qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
|
||||
}
|
||||
|
||||
qemu_set_irq(s->irq, !!(s->intreq & ~mask));
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
|
||||
{
|
||||
if (!s->active)
|
||||
return;
|
||||
|
||||
if (s->cmdat & CMDAT_WR_RD) {
|
||||
while (s->bytesleft && s->tx_len) {
|
||||
sdbus_write_byte(&s->sdbus, s->tx_fifo[s->tx_start++]);
|
||||
s->tx_start &= 0x1f;
|
||||
s->tx_len --;
|
||||
s->bytesleft --;
|
||||
}
|
||||
if (s->bytesleft)
|
||||
s->intreq |= INT_TXFIFO_REQ;
|
||||
} else
|
||||
while (s->bytesleft && s->rx_len < 32) {
|
||||
s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
|
||||
sdbus_read_byte(&s->sdbus);
|
||||
s->bytesleft --;
|
||||
s->intreq |= INT_RXFIFO_REQ;
|
||||
}
|
||||
|
||||
if (!s->bytesleft) {
|
||||
s->active = 0;
|
||||
s->intreq |= INT_DATA_DONE;
|
||||
s->status |= STAT_DATA_DONE;
|
||||
|
||||
if (s->cmdat & CMDAT_WR_RD) {
|
||||
s->intreq |= INT_PRG_DONE;
|
||||
s->status |= STAT_PRG_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
pxa2xx_mmci_int_update(s);
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
|
||||
{
|
||||
int rsplen, i;
|
||||
SDRequest request;
|
||||
uint8_t response[16];
|
||||
|
||||
s->active = 1;
|
||||
s->rx_len = 0;
|
||||
s->tx_len = 0;
|
||||
s->cmdreq = 0;
|
||||
|
||||
request.cmd = s->cmd;
|
||||
request.arg = s->arg;
|
||||
request.crc = 0; /* FIXME */
|
||||
|
||||
rsplen = sdbus_do_command(&s->sdbus, &request, response);
|
||||
s->intreq |= INT_END_CMD;
|
||||
|
||||
memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
|
||||
switch (s->cmdat & CMDAT_RES_TYPE) {
|
||||
#define PXAMMCI_RESP(wd, value0, value1) \
|
||||
s->resp_fifo[(wd) + 0] |= (value0); \
|
||||
s->resp_fifo[(wd) + 1] |= (value1) << 8;
|
||||
case 0: /* No response */
|
||||
goto complete;
|
||||
|
||||
case 1: /* R1, R4, R5 or R6 */
|
||||
if (rsplen < 4)
|
||||
goto timeout;
|
||||
goto complete;
|
||||
|
||||
case 2: /* R2 */
|
||||
if (rsplen < 16)
|
||||
goto timeout;
|
||||
goto complete;
|
||||
|
||||
case 3: /* R3 */
|
||||
if (rsplen < 4)
|
||||
goto timeout;
|
||||
goto complete;
|
||||
|
||||
complete:
|
||||
for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
|
||||
PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
|
||||
}
|
||||
s->status |= STAT_END_CMDRES;
|
||||
|
||||
if (!(s->cmdat & CMDAT_DATA_EN))
|
||||
s->active = 0;
|
||||
else
|
||||
s->bytesleft = s->numblk * s->blklen;
|
||||
|
||||
s->resp_len = 0;
|
||||
break;
|
||||
|
||||
timeout:
|
||||
s->active = 0;
|
||||
s->status |= STAT_TOUT_RES;
|
||||
break;
|
||||
}
|
||||
|
||||
pxa2xx_mmci_fifo_update(s);
|
||||
}
|
||||
|
||||
static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (offset) {
|
||||
case MMC_STRPCL:
|
||||
break;
|
||||
case MMC_STAT:
|
||||
ret = s->status;
|
||||
break;
|
||||
case MMC_CLKRT:
|
||||
ret = s->clkrt;
|
||||
break;
|
||||
case MMC_SPI:
|
||||
ret = s->spi;
|
||||
break;
|
||||
case MMC_CMDAT:
|
||||
ret = s->cmdat;
|
||||
break;
|
||||
case MMC_RESTO:
|
||||
ret = s->resp_tout;
|
||||
break;
|
||||
case MMC_RDTO:
|
||||
ret = s->read_tout;
|
||||
break;
|
||||
case MMC_BLKLEN:
|
||||
ret = s->blklen;
|
||||
break;
|
||||
case MMC_NUMBLK:
|
||||
ret = s->numblk;
|
||||
break;
|
||||
case MMC_PRTBUF:
|
||||
break;
|
||||
case MMC_I_MASK:
|
||||
ret = s->intmask;
|
||||
break;
|
||||
case MMC_I_REG:
|
||||
ret = s->intreq;
|
||||
break;
|
||||
case MMC_CMD:
|
||||
ret = s->cmd | 0x40;
|
||||
break;
|
||||
case MMC_ARGH:
|
||||
ret = s->arg >> 16;
|
||||
break;
|
||||
case MMC_ARGL:
|
||||
ret = s->arg & 0xffff;
|
||||
break;
|
||||
case MMC_RES:
|
||||
ret = (s->resp_len < 9) ? s->resp_fifo[s->resp_len++] : 0;
|
||||
break;
|
||||
case MMC_RXFIFO:
|
||||
while (size-- && s->rx_len) {
|
||||
ret |= s->rx_fifo[s->rx_start++] << (size << 3);
|
||||
s->rx_start &= 0x1f;
|
||||
s->rx_len --;
|
||||
}
|
||||
s->intreq &= ~INT_RXFIFO_REQ;
|
||||
pxa2xx_mmci_fifo_update(s);
|
||||
break;
|
||||
case MMC_RDWAIT:
|
||||
break;
|
||||
case MMC_BLKS_REM:
|
||||
ret = s->numblk;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: incorrect register 0x%02" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
trace_pxa2xx_mmci_read(size, offset, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_write(void *opaque,
|
||||
hwaddr offset, uint64_t value, unsigned size)
|
||||
{
|
||||
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
|
||||
|
||||
trace_pxa2xx_mmci_write(size, offset, value);
|
||||
switch (offset) {
|
||||
case MMC_STRPCL:
|
||||
if (value & STRPCL_STRT_CLK) {
|
||||
s->status |= STAT_CLK_EN;
|
||||
s->intreq &= ~INT_CLK_OFF;
|
||||
|
||||
if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
|
||||
s->status &= STAT_CLK_EN;
|
||||
pxa2xx_mmci_wakequeues(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (value & STRPCL_STOP_CLK) {
|
||||
s->status &= ~STAT_CLK_EN;
|
||||
s->intreq |= INT_CLK_OFF;
|
||||
s->active = 0;
|
||||
}
|
||||
|
||||
pxa2xx_mmci_int_update(s);
|
||||
break;
|
||||
|
||||
case MMC_CLKRT:
|
||||
s->clkrt = value & 7;
|
||||
break;
|
||||
|
||||
case MMC_SPI:
|
||||
s->spi = value & 0xf;
|
||||
if (value & SPI_SPI_MODE) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: attempted to use card in SPI mode\n", __func__);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC_CMDAT:
|
||||
s->cmdat = value & 0x3dff;
|
||||
s->active = 0;
|
||||
s->cmdreq = 1;
|
||||
if (!(value & CMDAT_STOP_TRAN)) {
|
||||
s->status &= STAT_CLK_EN;
|
||||
|
||||
if (s->status & STAT_CLK_EN)
|
||||
pxa2xx_mmci_wakequeues(s);
|
||||
}
|
||||
|
||||
pxa2xx_mmci_int_update(s);
|
||||
break;
|
||||
|
||||
case MMC_RESTO:
|
||||
s->resp_tout = value & 0x7f;
|
||||
break;
|
||||
|
||||
case MMC_RDTO:
|
||||
s->read_tout = value & 0xffff;
|
||||
break;
|
||||
|
||||
case MMC_BLKLEN:
|
||||
s->blklen = value & 0xfff;
|
||||
break;
|
||||
|
||||
case MMC_NUMBLK:
|
||||
s->numblk = value & 0xffff;
|
||||
break;
|
||||
|
||||
case MMC_PRTBUF:
|
||||
if (value & PRTBUF_PRT_BUF) {
|
||||
s->tx_start ^= 32;
|
||||
s->tx_len = 0;
|
||||
}
|
||||
pxa2xx_mmci_fifo_update(s);
|
||||
break;
|
||||
|
||||
case MMC_I_MASK:
|
||||
s->intmask = value & 0x1fff;
|
||||
pxa2xx_mmci_int_update(s);
|
||||
break;
|
||||
|
||||
case MMC_CMD:
|
||||
s->cmd = value & 0x3f;
|
||||
break;
|
||||
|
||||
case MMC_ARGH:
|
||||
s->arg &= 0x0000ffff;
|
||||
s->arg |= value << 16;
|
||||
break;
|
||||
|
||||
case MMC_ARGL:
|
||||
s->arg &= 0xffff0000;
|
||||
s->arg |= value & 0x0000ffff;
|
||||
break;
|
||||
|
||||
case MMC_TXFIFO:
|
||||
while (size-- && s->tx_len < 0x20)
|
||||
s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
|
||||
(value >> (size << 3)) & 0xff;
|
||||
s->intreq &= ~INT_TXFIFO_REQ;
|
||||
pxa2xx_mmci_fifo_update(s);
|
||||
break;
|
||||
|
||||
case MMC_RDWAIT:
|
||||
case MMC_BLKS_REM:
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: incorrect reg 0x%02" HWADDR_PRIx " "
|
||||
"(value 0x%08" PRIx64 ")\n", __func__, offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pxa2xx_mmci_ops = {
|
||||
.read = pxa2xx_mmci_read,
|
||||
.write = pxa2xx_mmci_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
|
||||
hwaddr base,
|
||||
qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = sysbus_create_simple(TYPE_PXA2XX_MMCI, base, irq);
|
||||
qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma);
|
||||
qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
|
||||
|
||||
return PXA2XX_MMCI(dev);
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
|
||||
{
|
||||
PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
|
||||
|
||||
qemu_set_irq(s->inserted, inserted);
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly)
|
||||
{
|
||||
PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
|
||||
|
||||
qemu_set_irq(s->readonly, readonly);
|
||||
}
|
||||
|
||||
void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
|
||||
qemu_irq coverswitch)
|
||||
{
|
||||
DeviceState *dev = DEVICE(s);
|
||||
|
||||
s->readonly = readonly;
|
||||
s->inserted = coverswitch;
|
||||
|
||||
pxa2xx_mmci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
|
||||
pxa2xx_mmci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_reset(DeviceState *d)
|
||||
{
|
||||
PXA2xxMMCIState *s = PXA2XX_MMCI(d);
|
||||
|
||||
s->status = 0;
|
||||
s->clkrt = 0;
|
||||
s->spi = 0;
|
||||
s->cmdat = 0;
|
||||
s->resp_tout = 0;
|
||||
s->read_tout = 0;
|
||||
s->blklen = 0;
|
||||
s->numblk = 0;
|
||||
s->intmask = 0;
|
||||
s->intreq = 0;
|
||||
s->cmd = 0;
|
||||
s->arg = 0;
|
||||
s->active = 0;
|
||||
s->bytesleft = 0;
|
||||
s->tx_start = 0;
|
||||
s->tx_len = 0;
|
||||
s->rx_start = 0;
|
||||
s->rx_len = 0;
|
||||
s->resp_len = 0;
|
||||
s->cmdreq = 0;
|
||||
memset(s->tx_fifo, 0, sizeof(s->tx_fifo));
|
||||
memset(s->rx_fifo, 0, sizeof(s->rx_fifo));
|
||||
memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_instance_init(Object *obj)
|
||||
{
|
||||
PXA2xxMMCIState *s = PXA2XX_MMCI(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_mmci_ops, s,
|
||||
"pxa2xx-mmci", 0x00100000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1);
|
||||
qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1);
|
||||
|
||||
qbus_init(&s->sdbus, sizeof(s->sdbus),
|
||||
TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_pxa2xx_mmci;
|
||||
device_class_set_legacy_reset(dc, pxa2xx_mmci_reset);
|
||||
}
|
||||
|
||||
static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SDBusClass *sbc = SD_BUS_CLASS(klass);
|
||||
|
||||
sbc->set_inserted = pxa2xx_mmci_set_inserted;
|
||||
sbc->set_readonly = pxa2xx_mmci_set_readonly;
|
||||
}
|
||||
|
||||
static const TypeInfo pxa2xx_mmci_types[] = {
|
||||
{
|
||||
.name = TYPE_PXA2XX_MMCI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PXA2xxMMCIState),
|
||||
.instance_init = pxa2xx_mmci_instance_init,
|
||||
.class_init = pxa2xx_mmci_class_init,
|
||||
},
|
||||
{
|
||||
.name = TYPE_PXA2XX_MMCI_BUS,
|
||||
.parent = TYPE_SD_BUS,
|
||||
.instance_size = sizeof(SDBus),
|
||||
.class_init = pxa2xx_mmci_bus_class_init,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(pxa2xx_mmci_types)
|
|
@ -774,19 +774,12 @@ static uint32_t sd_blk_len(SDState *sd)
|
|||
*/
|
||||
static uint32_t sd_bootpart_offset(SDState *sd)
|
||||
{
|
||||
bool partitions_enabled;
|
||||
unsigned partition_access;
|
||||
|
||||
if (!sd->boot_part_size || !sd_is_emmc(sd)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
partitions_enabled = sd->ext_csd[EXT_CSD_PART_CONFIG]
|
||||
& EXT_CSD_PART_CONFIG_EN_MASK;
|
||||
if (!partitions_enabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
partition_access = sd->ext_csd[EXT_CSD_PART_CONFIG]
|
||||
& EXT_CSD_PART_CONFIG_ACC_MASK;
|
||||
switch (partition_access) {
|
||||
|
|
|
@ -60,10 +60,6 @@ sdcard_set_voltage(uint16_t millivolts) "%u mV"
|
|||
sdcard_ext_csd_update(unsigned index, uint8_t oval, uint8_t nval) "index %u: 0x%02x -> 0x%02x"
|
||||
sdcard_switch(unsigned access, unsigned index, unsigned value, unsigned set) "SWITCH acc:%u idx:%u val:%u set:%u"
|
||||
|
||||
# pxa2xx_mmci.c
|
||||
pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
|
||||
pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
|
||||
|
||||
# pl181.c
|
||||
pl181_command_send(uint8_t cmd, uint32_t arg) "sending CMD%02d arg 0x%08" PRIx32
|
||||
pl181_command_sent(void) "command sent"
|
||||
|
|
|
@ -9,7 +9,6 @@ system_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c'))
|
|||
system_ss.add(when: 'CONFIG_XILINX_SPIPS', if_true: files('xilinx_spips.c'))
|
||||
system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c'))
|
||||
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c'))
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c'))
|
||||
system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c'))
|
||||
system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c'))
|
||||
system_ss.add(when: 'CONFIG_PNV_SPI', if_true: files('pnv_spi.c'))
|
||||
|
|
|
@ -1,380 +0,0 @@
|
|||
/*
|
||||
* TI OMAP processor's Multichannel SPI emulation.
|
||||
*
|
||||
* Copyright (C) 2007-2009 Nokia Corporation
|
||||
*
|
||||
* Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) any later version of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/arm/omap.h"
|
||||
|
||||
/* Multichannel SPI */
|
||||
struct omap_mcspi_s {
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
int chnum;
|
||||
|
||||
uint32_t sysconfig;
|
||||
uint32_t systest;
|
||||
uint32_t irqst;
|
||||
uint32_t irqen;
|
||||
uint32_t wken;
|
||||
uint32_t control;
|
||||
|
||||
struct omap_mcspi_ch_s {
|
||||
qemu_irq txdrq;
|
||||
qemu_irq rxdrq;
|
||||
uint32_t (*txrx)(void *opaque, uint32_t, int);
|
||||
void *opaque;
|
||||
|
||||
uint32_t tx;
|
||||
uint32_t rx;
|
||||
|
||||
uint32_t config;
|
||||
uint32_t status;
|
||||
uint32_t control;
|
||||
} ch[4];
|
||||
};
|
||||
|
||||
static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
|
||||
{
|
||||
qemu_set_irq(s->irq, s->irqst & s->irqen);
|
||||
}
|
||||
|
||||
static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
|
||||
{
|
||||
qemu_set_irq(ch->txdrq,
|
||||
(ch->control & 1) && /* EN */
|
||||
(ch->config & (1 << 14)) && /* DMAW */
|
||||
(ch->status & (1 << 1)) && /* TXS */
|
||||
((ch->config >> 12) & 3) != 1); /* TRM */
|
||||
qemu_set_irq(ch->rxdrq,
|
||||
(ch->control & 1) && /* EN */
|
||||
(ch->config & (1 << 15)) && /* DMAW */
|
||||
(ch->status & (1 << 0)) && /* RXS */
|
||||
((ch->config >> 12) & 3) != 2); /* TRM */
|
||||
}
|
||||
|
||||
static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
|
||||
{
|
||||
struct omap_mcspi_ch_s *ch = s->ch + chnum;
|
||||
|
||||
if (!(ch->control & 1)) /* EN */
|
||||
return;
|
||||
if ((ch->status & (1 << 0)) && /* RXS */
|
||||
((ch->config >> 12) & 3) != 2 && /* TRM */
|
||||
!(ch->config & (1 << 19))) /* TURBO */
|
||||
goto intr_update;
|
||||
if ((ch->status & (1 << 1)) && /* TXS */
|
||||
((ch->config >> 12) & 3) != 1) /* TRM */
|
||||
goto intr_update;
|
||||
|
||||
if (!(s->control & 1) || /* SINGLE */
|
||||
(ch->config & (1 << 20))) { /* FORCE */
|
||||
if (ch->txrx)
|
||||
ch->rx = ch->txrx(ch->opaque, ch->tx, /* WL */
|
||||
1 + (0x1f & (ch->config >> 7)));
|
||||
}
|
||||
|
||||
ch->tx = 0;
|
||||
ch->status |= 1 << 2; /* EOT */
|
||||
ch->status |= 1 << 1; /* TXS */
|
||||
if (((ch->config >> 12) & 3) != 2) /* TRM */
|
||||
ch->status |= 1 << 0; /* RXS */
|
||||
|
||||
intr_update:
|
||||
if ((ch->status & (1 << 0)) && /* RXS */
|
||||
((ch->config >> 12) & 3) != 2 && /* TRM */
|
||||
!(ch->config & (1 << 19))) /* TURBO */
|
||||
s->irqst |= 1 << (2 + 4 * chnum); /* RX_FULL */
|
||||
if ((ch->status & (1 << 1)) && /* TXS */
|
||||
((ch->config >> 12) & 3) != 1) /* TRM */
|
||||
s->irqst |= 1 << (0 + 4 * chnum); /* TX_EMPTY */
|
||||
omap_mcspi_interrupt_update(s);
|
||||
omap_mcspi_dmarequest_update(ch);
|
||||
}
|
||||
|
||||
void omap_mcspi_reset(struct omap_mcspi_s *s)
|
||||
{
|
||||
int ch;
|
||||
|
||||
s->sysconfig = 0;
|
||||
s->systest = 0;
|
||||
s->irqst = 0;
|
||||
s->irqen = 0;
|
||||
s->wken = 0;
|
||||
s->control = 4;
|
||||
|
||||
for (ch = 0; ch < 4; ch ++) {
|
||||
s->ch[ch].config = 0x060000;
|
||||
s->ch[ch].status = 2; /* TXS */
|
||||
s->ch[ch].control = 0;
|
||||
|
||||
omap_mcspi_dmarequest_update(s->ch + ch);
|
||||
}
|
||||
|
||||
omap_mcspi_interrupt_update(s);
|
||||
}
|
||||
|
||||
static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
struct omap_mcspi_s *s = opaque;
|
||||
int ch = 0;
|
||||
uint32_t ret;
|
||||
|
||||
if (size != 4) {
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* MCSPI_REVISION */
|
||||
return 0x91;
|
||||
|
||||
case 0x10: /* MCSPI_SYSCONFIG */
|
||||
return s->sysconfig;
|
||||
|
||||
case 0x14: /* MCSPI_SYSSTATUS */
|
||||
return 1; /* RESETDONE */
|
||||
|
||||
case 0x18: /* MCSPI_IRQSTATUS */
|
||||
return s->irqst;
|
||||
|
||||
case 0x1c: /* MCSPI_IRQENABLE */
|
||||
return s->irqen;
|
||||
|
||||
case 0x20: /* MCSPI_WAKEUPENABLE */
|
||||
return s->wken;
|
||||
|
||||
case 0x24: /* MCSPI_SYST */
|
||||
return s->systest;
|
||||
|
||||
case 0x28: /* MCSPI_MODULCTRL */
|
||||
return s->control;
|
||||
|
||||
case 0x68: ch ++;
|
||||
/* fall through */
|
||||
case 0x54: ch ++;
|
||||
/* fall through */
|
||||
case 0x40: ch ++;
|
||||
/* fall through */
|
||||
case 0x2c: /* MCSPI_CHCONF */
|
||||
return s->ch[ch].config;
|
||||
|
||||
case 0x6c: ch ++;
|
||||
/* fall through */
|
||||
case 0x58: ch ++;
|
||||
/* fall through */
|
||||
case 0x44: ch ++;
|
||||
/* fall through */
|
||||
case 0x30: /* MCSPI_CHSTAT */
|
||||
return s->ch[ch].status;
|
||||
|
||||
case 0x70: ch ++;
|
||||
/* fall through */
|
||||
case 0x5c: ch ++;
|
||||
/* fall through */
|
||||
case 0x48: ch ++;
|
||||
/* fall through */
|
||||
case 0x34: /* MCSPI_CHCTRL */
|
||||
return s->ch[ch].control;
|
||||
|
||||
case 0x74: ch ++;
|
||||
/* fall through */
|
||||
case 0x60: ch ++;
|
||||
/* fall through */
|
||||
case 0x4c: ch ++;
|
||||
/* fall through */
|
||||
case 0x38: /* MCSPI_TX */
|
||||
return s->ch[ch].tx;
|
||||
|
||||
case 0x78: ch ++;
|
||||
/* fall through */
|
||||
case 0x64: ch ++;
|
||||
/* fall through */
|
||||
case 0x50: ch ++;
|
||||
/* fall through */
|
||||
case 0x3c: /* MCSPI_RX */
|
||||
s->ch[ch].status &= ~(1 << 0); /* RXS */
|
||||
ret = s->ch[ch].rx;
|
||||
omap_mcspi_transfer_run(s, ch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_mcspi_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
struct omap_mcspi_s *s = opaque;
|
||||
int ch = 0;
|
||||
|
||||
if (size != 4) {
|
||||
omap_badwidth_write32(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* MCSPI_REVISION */
|
||||
case 0x14: /* MCSPI_SYSSTATUS */
|
||||
case 0x30: /* MCSPI_CHSTAT0 */
|
||||
case 0x3c: /* MCSPI_RX0 */
|
||||
case 0x44: /* MCSPI_CHSTAT1 */
|
||||
case 0x50: /* MCSPI_RX1 */
|
||||
case 0x58: /* MCSPI_CHSTAT2 */
|
||||
case 0x64: /* MCSPI_RX2 */
|
||||
case 0x6c: /* MCSPI_CHSTAT3 */
|
||||
case 0x78: /* MCSPI_RX3 */
|
||||
OMAP_RO_REG(addr);
|
||||
return;
|
||||
|
||||
case 0x10: /* MCSPI_SYSCONFIG */
|
||||
if (value & (1 << 1)) /* SOFTRESET */
|
||||
omap_mcspi_reset(s);
|
||||
s->sysconfig = value & 0x31d;
|
||||
break;
|
||||
|
||||
case 0x18: /* MCSPI_IRQSTATUS */
|
||||
if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
|
||||
s->irqst &= ~value;
|
||||
omap_mcspi_interrupt_update(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1c: /* MCSPI_IRQENABLE */
|
||||
s->irqen = value & 0x1777f;
|
||||
omap_mcspi_interrupt_update(s);
|
||||
break;
|
||||
|
||||
case 0x20: /* MCSPI_WAKEUPENABLE */
|
||||
s->wken = value & 1;
|
||||
break;
|
||||
|
||||
case 0x24: /* MCSPI_SYST */
|
||||
if (s->control & (1 << 3)) /* SYSTEM_TEST */
|
||||
if (value & (1 << 11)) { /* SSB */
|
||||
s->irqst |= 0x1777f;
|
||||
omap_mcspi_interrupt_update(s);
|
||||
}
|
||||
s->systest = value & 0xfff;
|
||||
break;
|
||||
|
||||
case 0x28: /* MCSPI_MODULCTRL */
|
||||
if (value & (1 << 3)) /* SYSTEM_TEST */
|
||||
if (s->systest & (1 << 11)) { /* SSB */
|
||||
s->irqst |= 0x1777f;
|
||||
omap_mcspi_interrupt_update(s);
|
||||
}
|
||||
s->control = value & 0xf;
|
||||
break;
|
||||
|
||||
case 0x68: ch ++;
|
||||
/* fall through */
|
||||
case 0x54: ch ++;
|
||||
/* fall through */
|
||||
case 0x40: ch ++;
|
||||
/* fall through */
|
||||
case 0x2c: /* MCSPI_CHCONF */
|
||||
if ((value ^ s->ch[ch].config) & (3 << 14)) /* DMAR | DMAW */
|
||||
omap_mcspi_dmarequest_update(s->ch + ch);
|
||||
if (((value >> 12) & 3) == 3) { /* TRM */
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid TRM value (3)\n",
|
||||
__func__);
|
||||
}
|
||||
if (((value >> 7) & 0x1f) < 3) { /* WL */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid WL value (%" PRIx64 ")\n",
|
||||
__func__, (value >> 7) & 0x1f);
|
||||
}
|
||||
s->ch[ch].config = value & 0x7fffff;
|
||||
break;
|
||||
|
||||
case 0x70: ch ++;
|
||||
/* fall through */
|
||||
case 0x5c: ch ++;
|
||||
/* fall through */
|
||||
case 0x48: ch ++;
|
||||
/* fall through */
|
||||
case 0x34: /* MCSPI_CHCTRL */
|
||||
if (value & ~s->ch[ch].control & 1) { /* EN */
|
||||
s->ch[ch].control |= 1;
|
||||
omap_mcspi_transfer_run(s, ch);
|
||||
} else
|
||||
s->ch[ch].control = value & 1;
|
||||
break;
|
||||
|
||||
case 0x74: ch ++;
|
||||
/* fall through */
|
||||
case 0x60: ch ++;
|
||||
/* fall through */
|
||||
case 0x4c: ch ++;
|
||||
/* fall through */
|
||||
case 0x38: /* MCSPI_TX */
|
||||
s->ch[ch].tx = value;
|
||||
s->ch[ch].status &= ~(1 << 1); /* TXS */
|
||||
omap_mcspi_transfer_run(s, ch);
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_mcspi_ops = {
|
||||
.read = omap_mcspi_read,
|
||||
.write = omap_mcspi_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
|
||||
qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
|
||||
{
|
||||
struct omap_mcspi_s *s = g_new0(struct omap_mcspi_s, 1);
|
||||
struct omap_mcspi_ch_s *ch = s->ch;
|
||||
|
||||
s->irq = irq;
|
||||
s->chnum = chnum;
|
||||
while (chnum --) {
|
||||
ch->txdrq = *drq ++;
|
||||
ch->rxdrq = *drq ++;
|
||||
ch ++;
|
||||
}
|
||||
omap_mcspi_reset(s);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_mcspi_ops, s, "omap.mcspi",
|
||||
omap_l4_region_size(ta, 0));
|
||||
omap_l4_attach(ta, 0, &s->iomem);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void omap_mcspi_attach(struct omap_mcspi_s *s,
|
||||
uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
|
||||
int chipselect)
|
||||
{
|
||||
if (chipselect < 0 || chipselect >= s->chnum)
|
||||
hw_error("%s: Bad chipselect %i\n", __func__, chipselect);
|
||||
|
||||
s->ch[chipselect].txrx = txrx;
|
||||
s->ch[chipselect].opaque = opaque;
|
||||
}
|
|
@ -620,7 +620,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
|
|||
} else if (s->snoop_state == SNOOP_STRIPING ||
|
||||
s->snoop_state == SNOOP_NONE) {
|
||||
for (i = 0; i < num_effective_busses(s); ++i) {
|
||||
tx_rx[i] = fifo8_pop(&s->tx_fifo);
|
||||
if (!fifo8_is_empty(&s->tx_fifo)) {
|
||||
tx_rx[i] = fifo8_pop(&s->tx_fifo);
|
||||
}
|
||||
}
|
||||
stripe8(tx_rx, num_effective_busses(s), false);
|
||||
} else if (s->snoop_state >= SNOOP_ADDR) {
|
||||
|
|
|
@ -21,6 +21,9 @@ config ALLWINNER_A10_PIT
|
|||
bool
|
||||
select PTIMER
|
||||
|
||||
config PXA2XX_TIMER
|
||||
bool
|
||||
|
||||
config SIFIVE_PWM
|
||||
bool
|
||||
|
||||
|
|
|
@ -21,9 +21,7 @@ system_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gictimer.c'))
|
|||
system_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-timer.c'))
|
||||
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_timer.c'))
|
||||
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_timer.c'))
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gptimer.c'))
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c'))
|
||||
system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c'))
|
||||
system_ss.add(when: 'CONFIG_PXA2XX_TIMER', if_true: files('pxa2xx_timer.c'))
|
||||
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c'))
|
||||
system_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c'))
|
||||
system_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_timer.c'))
|
||||
|
|
|
@ -1,512 +0,0 @@
|
|||
/*
|
||||
* TI OMAP2 general purpose timers emulation.
|
||||
*
|
||||
* Copyright (C) 2007-2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) any later version of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/arm/omap.h"
|
||||
|
||||
/* GP timers */
|
||||
struct omap_gp_timer_s {
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
qemu_irq wkup;
|
||||
qemu_irq in;
|
||||
qemu_irq out;
|
||||
omap_clk clk;
|
||||
QEMUTimer *timer;
|
||||
QEMUTimer *match;
|
||||
struct omap_target_agent_s *ta;
|
||||
|
||||
int in_val;
|
||||
int out_val;
|
||||
int64_t time;
|
||||
int64_t rate;
|
||||
int64_t ticks_per_sec;
|
||||
|
||||
int16_t config;
|
||||
int status;
|
||||
int it_ena;
|
||||
int wu_ena;
|
||||
int enable;
|
||||
int inout;
|
||||
int capt2;
|
||||
int pt;
|
||||
enum {
|
||||
gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
|
||||
} trigger;
|
||||
enum {
|
||||
gpt_capture_none, gpt_capture_rising,
|
||||
gpt_capture_falling, gpt_capture_both
|
||||
} capture;
|
||||
int scpwm;
|
||||
int ce;
|
||||
int pre;
|
||||
int ptv;
|
||||
int ar;
|
||||
int st;
|
||||
int posted;
|
||||
uint32_t val;
|
||||
uint32_t load_val;
|
||||
uint32_t capture_val[2];
|
||||
uint32_t match_val;
|
||||
int capt_num;
|
||||
|
||||
uint16_t writeh; /* LSB */
|
||||
uint16_t readh; /* MSB */
|
||||
};
|
||||
|
||||
#define GPT_TCAR_IT (1 << 2)
|
||||
#define GPT_OVF_IT (1 << 1)
|
||||
#define GPT_MAT_IT (1 << 0)
|
||||
|
||||
static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
|
||||
{
|
||||
if (timer->it_ena & it) {
|
||||
if (!timer->status)
|
||||
qemu_irq_raise(timer->irq);
|
||||
|
||||
timer->status |= it;
|
||||
/* Or are the status bits set even when masked?
|
||||
* i.e. is masking applied before or after the status register? */
|
||||
}
|
||||
|
||||
if (timer->wu_ena & it)
|
||||
qemu_irq_pulse(timer->wkup);
|
||||
}
|
||||
|
||||
static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
|
||||
{
|
||||
if (!timer->inout && timer->out_val != level) {
|
||||
timer->out_val = level;
|
||||
qemu_set_irq(timer->out, level);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
|
||||
{
|
||||
uint64_t distance;
|
||||
|
||||
if (timer->st && timer->rate) {
|
||||
distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time;
|
||||
distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
|
||||
|
||||
if (distance >= 0xffffffff - timer->val)
|
||||
return 0xffffffff;
|
||||
else
|
||||
return timer->val + distance;
|
||||
} else
|
||||
return timer->val;
|
||||
}
|
||||
|
||||
static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
|
||||
{
|
||||
if (timer->st) {
|
||||
timer->val = omap_gp_timer_read(timer);
|
||||
timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
|
||||
{
|
||||
int64_t expires, matches;
|
||||
|
||||
if (timer->st && timer->rate) {
|
||||
expires = muldiv64(0x100000000ll - timer->val,
|
||||
timer->ticks_per_sec, timer->rate);
|
||||
timer_mod(timer->timer, timer->time + expires);
|
||||
|
||||
if (timer->ce && timer->match_val >= timer->val) {
|
||||
matches = muldiv64(timer->ticks_per_sec,
|
||||
timer->match_val - timer->val, timer->rate);
|
||||
timer_mod(timer->match, timer->time + matches);
|
||||
} else
|
||||
timer_del(timer->match);
|
||||
} else {
|
||||
timer_del(timer->timer);
|
||||
timer_del(timer->match);
|
||||
omap_gp_timer_out(timer, timer->scpwm);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
|
||||
{
|
||||
if (timer->pt)
|
||||
/* TODO in overflow-and-match mode if the first event to
|
||||
* occur is the match, don't toggle. */
|
||||
omap_gp_timer_out(timer, !timer->out_val);
|
||||
else
|
||||
/* TODO inverted pulse on timer->out_val == 1? */
|
||||
qemu_irq_pulse(timer->out);
|
||||
}
|
||||
|
||||
static void omap_gp_timer_tick(void *opaque)
|
||||
{
|
||||
struct omap_gp_timer_s *timer = opaque;
|
||||
|
||||
if (!timer->ar) {
|
||||
timer->st = 0;
|
||||
timer->val = 0;
|
||||
} else {
|
||||
timer->val = timer->load_val;
|
||||
timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
}
|
||||
|
||||
if (timer->trigger == gpt_trigger_overflow ||
|
||||
timer->trigger == gpt_trigger_both)
|
||||
omap_gp_timer_trigger(timer);
|
||||
|
||||
omap_gp_timer_intr(timer, GPT_OVF_IT);
|
||||
omap_gp_timer_update(timer);
|
||||
}
|
||||
|
||||
static void omap_gp_timer_match(void *opaque)
|
||||
{
|
||||
struct omap_gp_timer_s *timer = opaque;
|
||||
|
||||
if (timer->trigger == gpt_trigger_both)
|
||||
omap_gp_timer_trigger(timer);
|
||||
|
||||
omap_gp_timer_intr(timer, GPT_MAT_IT);
|
||||
}
|
||||
|
||||
static void omap_gp_timer_input(void *opaque, int line, int on)
|
||||
{
|
||||
struct omap_gp_timer_s *s = opaque;
|
||||
int trigger;
|
||||
|
||||
switch (s->capture) {
|
||||
default:
|
||||
case gpt_capture_none:
|
||||
trigger = 0;
|
||||
break;
|
||||
case gpt_capture_rising:
|
||||
trigger = !s->in_val && on;
|
||||
break;
|
||||
case gpt_capture_falling:
|
||||
trigger = s->in_val && !on;
|
||||
break;
|
||||
case gpt_capture_both:
|
||||
trigger = (s->in_val == !on);
|
||||
break;
|
||||
}
|
||||
s->in_val = on;
|
||||
|
||||
if (s->inout && trigger && s->capt_num < 2) {
|
||||
s->capture_val[s->capt_num] = omap_gp_timer_read(s);
|
||||
|
||||
if (s->capt2 == s->capt_num ++)
|
||||
omap_gp_timer_intr(s, GPT_TCAR_IT);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_gp_timer_clk_update(void *opaque, int line, int on)
|
||||
{
|
||||
struct omap_gp_timer_s *timer = opaque;
|
||||
|
||||
omap_gp_timer_sync(timer);
|
||||
timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
|
||||
omap_gp_timer_update(timer);
|
||||
}
|
||||
|
||||
static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
|
||||
{
|
||||
omap_clk_adduser(timer->clk,
|
||||
qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0));
|
||||
timer->rate = omap_clk_getrate(timer->clk);
|
||||
}
|
||||
|
||||
void omap_gp_timer_reset(struct omap_gp_timer_s *s)
|
||||
{
|
||||
s->config = 0x000;
|
||||
s->status = 0;
|
||||
s->it_ena = 0;
|
||||
s->wu_ena = 0;
|
||||
s->inout = 0;
|
||||
s->capt2 = 0;
|
||||
s->capt_num = 0;
|
||||
s->pt = 0;
|
||||
s->trigger = gpt_trigger_none;
|
||||
s->capture = gpt_capture_none;
|
||||
s->scpwm = 0;
|
||||
s->ce = 0;
|
||||
s->pre = 0;
|
||||
s->ptv = 0;
|
||||
s->ar = 0;
|
||||
s->st = 0;
|
||||
s->posted = 1;
|
||||
s->val = 0x00000000;
|
||||
s->load_val = 0x00000000;
|
||||
s->capture_val[0] = 0x00000000;
|
||||
s->capture_val[1] = 0x00000000;
|
||||
s->match_val = 0x00000000;
|
||||
omap_gp_timer_update(s);
|
||||
}
|
||||
|
||||
static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
|
||||
{
|
||||
struct omap_gp_timer_s *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* TIDR */
|
||||
return 0x21;
|
||||
|
||||
case 0x10: /* TIOCP_CFG */
|
||||
return s->config;
|
||||
|
||||
case 0x14: /* TISTAT */
|
||||
/* ??? When's this bit reset? */
|
||||
return 1; /* RESETDONE */
|
||||
|
||||
case 0x18: /* TISR */
|
||||
return s->status;
|
||||
|
||||
case 0x1c: /* TIER */
|
||||
return s->it_ena;
|
||||
|
||||
case 0x20: /* TWER */
|
||||
return s->wu_ena;
|
||||
|
||||
case 0x24: /* TCLR */
|
||||
return (s->inout << 14) |
|
||||
(s->capt2 << 13) |
|
||||
(s->pt << 12) |
|
||||
(s->trigger << 10) |
|
||||
(s->capture << 8) |
|
||||
(s->scpwm << 7) |
|
||||
(s->ce << 6) |
|
||||
(s->pre << 5) |
|
||||
(s->ptv << 2) |
|
||||
(s->ar << 1) |
|
||||
(s->st << 0);
|
||||
|
||||
case 0x28: /* TCRR */
|
||||
return omap_gp_timer_read(s);
|
||||
|
||||
case 0x2c: /* TLDR */
|
||||
return s->load_val;
|
||||
|
||||
case 0x30: /* TTGR */
|
||||
return 0xffffffff;
|
||||
|
||||
case 0x34: /* TWPS */
|
||||
return 0x00000000; /* No posted writes pending. */
|
||||
|
||||
case 0x38: /* TMAR */
|
||||
return s->match_val;
|
||||
|
||||
case 0x3c: /* TCAR1 */
|
||||
return s->capture_val[0];
|
||||
|
||||
case 0x40: /* TSICR */
|
||||
return s->posted << 2;
|
||||
|
||||
case 0x44: /* TCAR2 */
|
||||
return s->capture_val[1];
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
|
||||
{
|
||||
struct omap_gp_timer_s *s = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
if (addr & 2)
|
||||
return s->readh;
|
||||
else {
|
||||
ret = omap_gp_timer_readw(opaque, addr);
|
||||
s->readh = ret >> 16;
|
||||
return ret & 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_gp_timer_write(void *opaque, hwaddr addr, uint32_t value)
|
||||
{
|
||||
struct omap_gp_timer_s *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* TIDR */
|
||||
case 0x14: /* TISTAT */
|
||||
case 0x34: /* TWPS */
|
||||
case 0x3c: /* TCAR1 */
|
||||
case 0x44: /* TCAR2 */
|
||||
OMAP_RO_REG(addr);
|
||||
break;
|
||||
|
||||
case 0x10: /* TIOCP_CFG */
|
||||
s->config = value & 0x33d;
|
||||
if (((value >> 3) & 3) == 3) /* IDLEMODE */
|
||||
fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
|
||||
__func__);
|
||||
if (value & 2) /* SOFTRESET */
|
||||
omap_gp_timer_reset(s);
|
||||
break;
|
||||
|
||||
case 0x18: /* TISR */
|
||||
if (value & GPT_TCAR_IT)
|
||||
s->capt_num = 0;
|
||||
if (s->status && !(s->status &= ~value))
|
||||
qemu_irq_lower(s->irq);
|
||||
break;
|
||||
|
||||
case 0x1c: /* TIER */
|
||||
s->it_ena = value & 7;
|
||||
break;
|
||||
|
||||
case 0x20: /* TWER */
|
||||
s->wu_ena = value & 7;
|
||||
break;
|
||||
|
||||
case 0x24: /* TCLR */
|
||||
omap_gp_timer_sync(s);
|
||||
s->inout = (value >> 14) & 1;
|
||||
s->capt2 = (value >> 13) & 1;
|
||||
s->pt = (value >> 12) & 1;
|
||||
s->trigger = (value >> 10) & 3;
|
||||
if (s->capture == gpt_capture_none &&
|
||||
((value >> 8) & 3) != gpt_capture_none)
|
||||
s->capt_num = 0;
|
||||
s->capture = (value >> 8) & 3;
|
||||
s->scpwm = (value >> 7) & 1;
|
||||
s->ce = (value >> 6) & 1;
|
||||
s->pre = (value >> 5) & 1;
|
||||
s->ptv = (value >> 2) & 7;
|
||||
s->ar = (value >> 1) & 1;
|
||||
s->st = (value >> 0) & 1;
|
||||
if (s->inout && s->trigger != gpt_trigger_none)
|
||||
fprintf(stderr, "%s: GP timer pin must be an output "
|
||||
"for this trigger mode\n", __func__);
|
||||
if (!s->inout && s->capture != gpt_capture_none)
|
||||
fprintf(stderr, "%s: GP timer pin must be an input "
|
||||
"for this capture mode\n", __func__);
|
||||
if (s->trigger == gpt_trigger_none)
|
||||
omap_gp_timer_out(s, s->scpwm);
|
||||
/* TODO: make sure this doesn't overflow 32-bits */
|
||||
s->ticks_per_sec = NANOSECONDS_PER_SECOND << (s->pre ? s->ptv + 1 : 0);
|
||||
omap_gp_timer_update(s);
|
||||
break;
|
||||
|
||||
case 0x28: /* TCRR */
|
||||
s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
s->val = value;
|
||||
omap_gp_timer_update(s);
|
||||
break;
|
||||
|
||||
case 0x2c: /* TLDR */
|
||||
s->load_val = value;
|
||||
break;
|
||||
|
||||
case 0x30: /* TTGR */
|
||||
s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
s->val = s->load_val;
|
||||
omap_gp_timer_update(s);
|
||||
break;
|
||||
|
||||
case 0x38: /* TMAR */
|
||||
omap_gp_timer_sync(s);
|
||||
s->match_val = value;
|
||||
omap_gp_timer_update(s);
|
||||
break;
|
||||
|
||||
case 0x40: /* TSICR */
|
||||
s->posted = (value >> 2) & 1;
|
||||
if (value & 2) /* How much exactly are we supposed to reset? */
|
||||
omap_gp_timer_reset(s);
|
||||
break;
|
||||
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_gp_timer_writeh(void *opaque, hwaddr addr, uint32_t value)
|
||||
{
|
||||
struct omap_gp_timer_s *s = opaque;
|
||||
|
||||
if (addr & 2)
|
||||
omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
|
||||
else
|
||||
s->writeh = (uint16_t) value;
|
||||
}
|
||||
|
||||
static uint64_t omap_gp_timer_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
case 2:
|
||||
return omap_gp_timer_readh(opaque, addr);
|
||||
case 4:
|
||||
return omap_gp_timer_readw(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_gp_timer_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
omap_badwidth_write32(opaque, addr, value);
|
||||
break;
|
||||
case 2:
|
||||
omap_gp_timer_writeh(opaque, addr, value);
|
||||
break;
|
||||
case 4:
|
||||
omap_gp_timer_write(opaque, addr, value);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_gp_timer_ops = {
|
||||
.read = omap_gp_timer_readfn,
|
||||
.write = omap_gp_timer_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
|
||||
qemu_irq irq, omap_clk fclk, omap_clk iclk)
|
||||
{
|
||||
struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
|
||||
|
||||
s->ta = ta;
|
||||
s->irq = irq;
|
||||
s->clk = fclk;
|
||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s);
|
||||
s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s);
|
||||
s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0);
|
||||
omap_gp_timer_reset(s);
|
||||
omap_gp_timer_clk_setup(s);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer",
|
||||
omap_l4_region_size(ta, 0));
|
||||
omap_l4_attach(ta, 0, &s->iomem);
|
||||
|
||||
return s;
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* TI OMAP2 32kHz sync timer emulation.
|
||||
*
|
||||
* Copyright (C) 2007-2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) any later version of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/arm/omap.h"
|
||||
struct omap_synctimer_s {
|
||||
MemoryRegion iomem;
|
||||
uint32_t val;
|
||||
uint16_t readh;
|
||||
};
|
||||
|
||||
/* 32-kHz Sync Timer of the OMAP2 */
|
||||
static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
|
||||
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 0x8000,
|
||||
NANOSECONDS_PER_SECOND);
|
||||
}
|
||||
|
||||
void omap_synctimer_reset(struct omap_synctimer_s *s)
|
||||
{
|
||||
s->val = omap_synctimer_read(s);
|
||||
}
|
||||
|
||||
static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
|
||||
{
|
||||
struct omap_synctimer_s *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* 32KSYNCNT_REV */
|
||||
return 0x21;
|
||||
|
||||
case 0x10: /* CR */
|
||||
return omap_synctimer_read(s) - s->val;
|
||||
}
|
||||
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
|
||||
{
|
||||
struct omap_synctimer_s *s = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
if (addr & 2)
|
||||
return s->readh;
|
||||
else {
|
||||
ret = omap_synctimer_readw(opaque, addr);
|
||||
s->readh = ret >> 16;
|
||||
return ret & 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t omap_synctimer_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
case 2:
|
||||
return omap_synctimer_readh(opaque, addr);
|
||||
case 4:
|
||||
return omap_synctimer_readw(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_synctimer_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_synctimer_ops = {
|
||||
.read = omap_synctimer_readfn,
|
||||
.write = omap_synctimer_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
|
||||
struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
|
||||
{
|
||||
struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
|
||||
|
||||
omap_synctimer_reset(s);
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_synctimer_ops, s, "omap.synctimer",
|
||||
omap_l4_region_size(ta, 0));
|
||||
omap_l4_attach(ta, 0, &s->iomem);
|
||||
|
||||
return s;
|
||||
}
|
|
@ -12,7 +12,6 @@
|
|||
#include "hw/qdev-properties.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/log.h"
|
||||
|
@ -55,7 +54,6 @@
|
|||
#define OSNR 0x20
|
||||
|
||||
#define PXA25X_FREQ 3686400 /* 3.6864 MHz */
|
||||
#define PXA27X_FREQ 3250000 /* 3.25 MHz */
|
||||
|
||||
static int pxa2xx_timer4_freq[8] = {
|
||||
[0] = 0,
|
||||
|
@ -573,28 +571,6 @@ static const TypeInfo pxa25x_timer_dev_info = {
|
|||
.class_init = pxa25x_timer_dev_class_init,
|
||||
};
|
||||
|
||||
static Property pxa27x_timer_dev_properties[] = {
|
||||
DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
|
||||
DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
|
||||
PXA2XX_TIMER_HAVE_TM4, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "PXA27x timer";
|
||||
device_class_set_props(dc, pxa27x_timer_dev_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo pxa27x_timer_dev_info = {
|
||||
.name = "pxa27x-timer",
|
||||
.parent = TYPE_PXA2XX_TIMER,
|
||||
.instance_size = sizeof(PXA2xxTimerInfo),
|
||||
.class_init = pxa27x_timer_dev_class_init,
|
||||
};
|
||||
|
||||
static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
@ -616,7 +592,6 @@ static void pxa2xx_timer_register_types(void)
|
|||
{
|
||||
type_register_static(&pxa2xx_timer_type_info);
|
||||
type_register_static(&pxa25x_timer_dev_info);
|
||||
type_register_static(&pxa27x_timer_dev_info);
|
||||
}
|
||||
|
||||
type_init(pxa2xx_timer_register_types)
|
||||
|
|
|
@ -53,18 +53,10 @@ config USB_XHCI_SYSBUS
|
|||
bool
|
||||
select USB_XHCI
|
||||
|
||||
config USB_MUSB
|
||||
bool
|
||||
select USB
|
||||
|
||||
config USB_DWC2
|
||||
bool
|
||||
select USB
|
||||
|
||||
config TUSB6010
|
||||
bool
|
||||
select USB_MUSB
|
||||
|
||||
config USB_HUB
|
||||
bool
|
||||
default y
|
||||
|
|
1553
hw/usb/hcd-musb.c
1553
hw/usb/hcd-musb.c
File diff suppressed because it is too large
Load Diff
|
@ -23,11 +23,9 @@ system_ss.add(when: 'CONFIG_USB_XHCI', if_true: files('hcd-xhci.c'))
|
|||
system_ss.add(when: 'CONFIG_USB_XHCI_PCI', if_true: files('hcd-xhci-pci.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_XHCI_SYSBUS', if_true: files('hcd-xhci-sysbus.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_XHCI_NEC', if_true: files('hcd-xhci-nec.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_MUSB', if_true: files('hcd-musb.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_DWC2', if_true: files('hcd-dwc2.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_DWC3', if_true: files('hcd-dwc3.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_TUSB6010', if_true: files('tusb6010.c'))
|
||||
system_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c'))
|
||||
system_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c'))
|
||||
system_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686-uhci-pci.c'))
|
||||
|
|
|
@ -1,850 +0,0 @@
|
|||
/*
|
||||
* Texas Instruments TUSB6010 emulation.
|
||||
* Based on reverse-engineering of a linux driver.
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/usb.h"
|
||||
#include "hw/usb/hcd-musb.h"
|
||||
#include "hw/arm/omap.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_TUSB6010 "tusb6010"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(TUSBState, TUSB6010)
|
||||
|
||||
struct TUSBState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem[2];
|
||||
qemu_irq irq;
|
||||
MUSBState *musb;
|
||||
QEMUTimer *otg_timer;
|
||||
QEMUTimer *pwr_timer;
|
||||
|
||||
int power;
|
||||
uint32_t scratch;
|
||||
uint16_t test_reset;
|
||||
uint32_t prcm_config;
|
||||
uint32_t prcm_mngmt;
|
||||
uint16_t otg_status;
|
||||
uint32_t dev_config;
|
||||
int host_mode;
|
||||
uint32_t intr;
|
||||
uint32_t intr_ok;
|
||||
uint32_t mask;
|
||||
uint32_t usbip_intr;
|
||||
uint32_t usbip_mask;
|
||||
uint32_t gpio_intr;
|
||||
uint32_t gpio_mask;
|
||||
uint32_t gpio_config;
|
||||
uint32_t dma_intr;
|
||||
uint32_t dma_mask;
|
||||
uint32_t dma_map;
|
||||
uint32_t dma_config;
|
||||
uint32_t ep0_config;
|
||||
uint32_t rx_config[15];
|
||||
uint32_t tx_config[15];
|
||||
uint32_t wkup_mask;
|
||||
uint32_t pullup[2];
|
||||
uint32_t control_config;
|
||||
uint32_t otg_timer_val;
|
||||
};
|
||||
|
||||
#define TUSB_DEVCLOCK 60000000 /* 60 MHz */
|
||||
|
||||
#define TUSB_VLYNQ_CTRL 0x004
|
||||
|
||||
/* Mentor Graphics OTG core registers. */
|
||||
#define TUSB_BASE_OFFSET 0x400
|
||||
|
||||
/* FIFO registers, 32-bit. */
|
||||
#define TUSB_FIFO_BASE 0x600
|
||||
|
||||
/* Device System & Control registers, 32-bit. */
|
||||
#define TUSB_SYS_REG_BASE 0x800
|
||||
|
||||
#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000)
|
||||
#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16)
|
||||
#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15)
|
||||
#define TUSB_DEV_CONF_SOFT_ID (1 << 1)
|
||||
#define TUSB_DEV_CONF_ID_SEL (1 << 0)
|
||||
|
||||
#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004)
|
||||
#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008)
|
||||
#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24)
|
||||
#define TUSB_PHY_OTG_CTRL_O_ID_PULLUP (1 << 23)
|
||||
#define TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
|
||||
#define TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
|
||||
#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17)
|
||||
#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16)
|
||||
#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15)
|
||||
#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14)
|
||||
#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13)
|
||||
#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12)
|
||||
#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11)
|
||||
#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10)
|
||||
#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9)
|
||||
#define TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
|
||||
#define TUSB_PHY_OTG_CTRL_PD (1 << 6)
|
||||
#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5)
|
||||
#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4)
|
||||
#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3)
|
||||
#define TUSB_PHY_OTG_CTRL_RESET (1 << 2)
|
||||
#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1)
|
||||
#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0)
|
||||
|
||||
/* OTG status register */
|
||||
#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c)
|
||||
#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8)
|
||||
#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7)
|
||||
#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6)
|
||||
#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5)
|
||||
#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4)
|
||||
#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3)
|
||||
#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2)
|
||||
#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0)
|
||||
#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1)
|
||||
#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0)
|
||||
|
||||
#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010)
|
||||
#define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31)
|
||||
#define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff)
|
||||
#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014)
|
||||
|
||||
/* PRCM configuration register */
|
||||
#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018)
|
||||
#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24)
|
||||
#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16)
|
||||
|
||||
/* PRCM management register */
|
||||
#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c)
|
||||
#define TUSB_PRCM_MNGMT_SRP_FIX_TMR(v) (((v) & 0xf) << 25)
|
||||
#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24)
|
||||
#define TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
|
||||
#define TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
|
||||
#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18)
|
||||
#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17)
|
||||
#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
|
||||
#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
|
||||
#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8)
|
||||
#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4)
|
||||
#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3)
|
||||
#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2)
|
||||
#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1)
|
||||
#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0)
|
||||
|
||||
/* Wake-up source clear and mask registers */
|
||||
#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020)
|
||||
#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028)
|
||||
#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c)
|
||||
#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13)
|
||||
#define TUSB_PRCM_WGPIO_7 (1 << 12)
|
||||
#define TUSB_PRCM_WGPIO_6 (1 << 11)
|
||||
#define TUSB_PRCM_WGPIO_5 (1 << 10)
|
||||
#define TUSB_PRCM_WGPIO_4 (1 << 9)
|
||||
#define TUSB_PRCM_WGPIO_3 (1 << 8)
|
||||
#define TUSB_PRCM_WGPIO_2 (1 << 7)
|
||||
#define TUSB_PRCM_WGPIO_1 (1 << 6)
|
||||
#define TUSB_PRCM_WGPIO_0 (1 << 5)
|
||||
#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */
|
||||
#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */
|
||||
#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */
|
||||
#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */
|
||||
#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */
|
||||
|
||||
#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030)
|
||||
#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034)
|
||||
#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038)
|
||||
#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c)
|
||||
#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040)
|
||||
#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044)
|
||||
#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048)
|
||||
#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c)
|
||||
#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050)
|
||||
#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054)
|
||||
#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058)
|
||||
#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c)
|
||||
#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060)
|
||||
#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064)
|
||||
#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068)
|
||||
#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c)
|
||||
|
||||
/* NOR flash interrupt source registers */
|
||||
#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070)
|
||||
#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074)
|
||||
#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078)
|
||||
#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c)
|
||||
#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24)
|
||||
#define TUSB_INT_SRC_USB_IP_CORE (1 << 17)
|
||||
#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16)
|
||||
#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15)
|
||||
#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14)
|
||||
#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13)
|
||||
#define TUSB_INT_SRC_DEV_READY (1 << 12)
|
||||
#define TUSB_INT_SRC_USB_IP_TX (1 << 9)
|
||||
#define TUSB_INT_SRC_USB_IP_RX (1 << 8)
|
||||
#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7)
|
||||
#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6)
|
||||
#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5)
|
||||
#define TUSB_INT_SRC_USB_IP_CONN (1 << 4)
|
||||
#define TUSB_INT_SRC_USB_IP_SOF (1 << 3)
|
||||
#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2)
|
||||
#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1)
|
||||
#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0)
|
||||
|
||||
#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080)
|
||||
#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084)
|
||||
#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100)
|
||||
#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104)
|
||||
#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108)
|
||||
#define TUSB_EP_IN_SIZE (TUSB_SYS_REG_BASE + 0x10c)
|
||||
#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148)
|
||||
#define TUSB_EP_OUT_SIZE (TUSB_SYS_REG_BASE + 0x14c)
|
||||
#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
|
||||
#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4)
|
||||
#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8)
|
||||
#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8)
|
||||
|
||||
#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8)
|
||||
#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc)
|
||||
|
||||
/* Device System & Control register bitfields */
|
||||
#define TUSB_INT_CTRL_CONF_INT_RLCYC(v) (((v) & 0x7) << 18)
|
||||
#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17)
|
||||
#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16)
|
||||
#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24)
|
||||
#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26)
|
||||
#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
|
||||
#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v) (((v) & 0xf) << 16)
|
||||
#define TUSB_EP0_CONFIG_SW_EN (1 << 8)
|
||||
#define TUSB_EP0_CONFIG_DIR_TX (1 << 7)
|
||||
#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f)
|
||||
#define TUSB_EP_CONFIG_SW_EN (1 << 31)
|
||||
#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff)
|
||||
#define TUSB_PROD_TEST_RESET_VAL 0xa596
|
||||
|
||||
static void tusb_intr_update(TUSBState *s)
|
||||
{
|
||||
if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
|
||||
qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
|
||||
else
|
||||
qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
|
||||
}
|
||||
|
||||
static void tusb_usbip_intr_update(TUSBState *s)
|
||||
{
|
||||
/* TX interrupt in the MUSB */
|
||||
if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
|
||||
s->intr |= TUSB_INT_SRC_USB_IP_TX;
|
||||
else
|
||||
s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
|
||||
|
||||
/* RX interrupt in the MUSB */
|
||||
if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
|
||||
s->intr |= TUSB_INT_SRC_USB_IP_RX;
|
||||
else
|
||||
s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
|
||||
|
||||
/* XXX: What about TUSB_INT_SRC_USB_IP_CORE? */
|
||||
|
||||
tusb_intr_update(s);
|
||||
}
|
||||
|
||||
static void tusb_dma_intr_update(TUSBState *s)
|
||||
{
|
||||
if (s->dma_intr & ~s->dma_mask)
|
||||
s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
|
||||
else
|
||||
s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
|
||||
|
||||
tusb_intr_update(s);
|
||||
}
|
||||
|
||||
static void tusb_gpio_intr_update(TUSBState *s)
|
||||
{
|
||||
/* TODO: How is this signalled? */
|
||||
}
|
||||
|
||||
static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
|
||||
switch (addr & 0xfff) {
|
||||
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
|
||||
return musb_read[0](s->musb, addr & 0x1ff);
|
||||
|
||||
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
|
||||
return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
|
||||
}
|
||||
|
||||
printf("%s: unknown register at %03x\n",
|
||||
__func__, (int) (addr & 0xfff));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
|
||||
switch (addr & 0xfff) {
|
||||
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
|
||||
return musb_read[1](s->musb, addr & 0x1ff);
|
||||
|
||||
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
|
||||
return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
|
||||
}
|
||||
|
||||
printf("%s: unknown register at %03x\n",
|
||||
__func__, (int) (addr & 0xfff));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
int offset = addr & 0xfff;
|
||||
int epnum;
|
||||
uint32_t ret;
|
||||
|
||||
switch (offset) {
|
||||
case TUSB_DEV_CONF:
|
||||
return s->dev_config;
|
||||
|
||||
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
|
||||
return musb_read[2](s->musb, offset & 0x1ff);
|
||||
|
||||
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
|
||||
return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
|
||||
|
||||
case TUSB_PHY_OTG_CTRL_ENABLE:
|
||||
case TUSB_PHY_OTG_CTRL:
|
||||
return 0x00; /* TODO */
|
||||
|
||||
case TUSB_DEV_OTG_STAT:
|
||||
ret = s->otg_status;
|
||||
#if 0
|
||||
if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
|
||||
ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
|
||||
#endif
|
||||
return ret;
|
||||
case TUSB_DEV_OTG_TIMER:
|
||||
return s->otg_timer_val;
|
||||
|
||||
case TUSB_PRCM_REV:
|
||||
return 0x20;
|
||||
case TUSB_PRCM_CONF:
|
||||
return s->prcm_config;
|
||||
case TUSB_PRCM_MNGMT:
|
||||
return s->prcm_mngmt;
|
||||
case TUSB_PRCM_WAKEUP_SOURCE:
|
||||
case TUSB_PRCM_WAKEUP_CLEAR: /* TODO: What does this one return? */
|
||||
return 0x00000000;
|
||||
case TUSB_PRCM_WAKEUP_MASK:
|
||||
return s->wkup_mask;
|
||||
|
||||
case TUSB_PULLUP_1_CTRL:
|
||||
return s->pullup[0];
|
||||
case TUSB_PULLUP_2_CTRL:
|
||||
return s->pullup[1];
|
||||
|
||||
case TUSB_INT_CTRL_REV:
|
||||
return 0x20;
|
||||
case TUSB_INT_CTRL_CONF:
|
||||
return s->control_config;
|
||||
|
||||
case TUSB_USBIP_INT_SRC:
|
||||
case TUSB_USBIP_INT_SET: /* TODO: What do these two return? */
|
||||
case TUSB_USBIP_INT_CLEAR:
|
||||
return s->usbip_intr;
|
||||
case TUSB_USBIP_INT_MASK:
|
||||
return s->usbip_mask;
|
||||
|
||||
case TUSB_DMA_INT_SRC:
|
||||
case TUSB_DMA_INT_SET: /* TODO: What do these two return? */
|
||||
case TUSB_DMA_INT_CLEAR:
|
||||
return s->dma_intr;
|
||||
case TUSB_DMA_INT_MASK:
|
||||
return s->dma_mask;
|
||||
|
||||
case TUSB_GPIO_INT_SRC: /* TODO: What do these two return? */
|
||||
case TUSB_GPIO_INT_SET:
|
||||
case TUSB_GPIO_INT_CLEAR:
|
||||
return s->gpio_intr;
|
||||
case TUSB_GPIO_INT_MASK:
|
||||
return s->gpio_mask;
|
||||
|
||||
case TUSB_INT_SRC:
|
||||
case TUSB_INT_SRC_SET: /* TODO: What do these two return? */
|
||||
case TUSB_INT_SRC_CLEAR:
|
||||
return s->intr;
|
||||
case TUSB_INT_MASK:
|
||||
return s->mask;
|
||||
|
||||
case TUSB_GPIO_REV:
|
||||
return 0x30;
|
||||
case TUSB_GPIO_CONF:
|
||||
return s->gpio_config;
|
||||
|
||||
case TUSB_DMA_CTRL_REV:
|
||||
return 0x30;
|
||||
case TUSB_DMA_REQ_CONF:
|
||||
return s->dma_config;
|
||||
case TUSB_EP0_CONF:
|
||||
return s->ep0_config;
|
||||
case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
|
||||
epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
|
||||
return s->tx_config[epnum];
|
||||
case TUSB_DMA_EP_MAP:
|
||||
return s->dma_map;
|
||||
case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
|
||||
epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
|
||||
return s->rx_config[epnum];
|
||||
case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
|
||||
(TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
|
||||
return 0x00000000; /* TODO */
|
||||
case TUSB_WAIT_COUNT:
|
||||
return 0x00; /* TODO */
|
||||
|
||||
case TUSB_SCRATCH_PAD:
|
||||
return s->scratch;
|
||||
|
||||
case TUSB_PROD_TEST_RESET:
|
||||
return s->test_reset;
|
||||
|
||||
/* DIE IDs */
|
||||
case TUSB_DIDR1_LO:
|
||||
return 0xa9453c59;
|
||||
case TUSB_DIDR1_HI:
|
||||
return 0x54059adf;
|
||||
}
|
||||
|
||||
printf("%s: unknown register at %03x\n", __func__, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tusb_async_writeb(void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
|
||||
switch (addr & 0xfff) {
|
||||
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
|
||||
musb_write[0](s->musb, addr & 0x1ff, value);
|
||||
break;
|
||||
|
||||
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
|
||||
musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: unknown register at %03x\n",
|
||||
__func__, (int) (addr & 0xfff));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void tusb_async_writeh(void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
|
||||
switch (addr & 0xfff) {
|
||||
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
|
||||
musb_write[1](s->musb, addr & 0x1ff, value);
|
||||
break;
|
||||
|
||||
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
|
||||
musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: unknown register at %03x\n",
|
||||
__func__, (int) (addr & 0xfff));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void tusb_async_writew(void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
int offset = addr & 0xfff;
|
||||
int epnum;
|
||||
|
||||
switch (offset) {
|
||||
case TUSB_VLYNQ_CTRL:
|
||||
break;
|
||||
|
||||
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
|
||||
musb_write[2](s->musb, offset & 0x1ff, value);
|
||||
break;
|
||||
|
||||
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
|
||||
musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
|
||||
break;
|
||||
|
||||
case TUSB_DEV_CONF:
|
||||
s->dev_config = value;
|
||||
s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
|
||||
if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
|
||||
hw_error("%s: Product Test mode not allowed\n", __func__);
|
||||
break;
|
||||
|
||||
case TUSB_PHY_OTG_CTRL_ENABLE:
|
||||
case TUSB_PHY_OTG_CTRL:
|
||||
return; /* TODO */
|
||||
case TUSB_DEV_OTG_TIMER:
|
||||
s->otg_timer_val = value;
|
||||
if (value & TUSB_DEV_OTG_TIMER_ENABLE)
|
||||
timer_mod(s->otg_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
|
||||
NANOSECONDS_PER_SECOND, TUSB_DEVCLOCK));
|
||||
else
|
||||
timer_del(s->otg_timer);
|
||||
break;
|
||||
|
||||
case TUSB_PRCM_CONF:
|
||||
s->prcm_config = value;
|
||||
break;
|
||||
case TUSB_PRCM_MNGMT:
|
||||
s->prcm_mngmt = value;
|
||||
break;
|
||||
case TUSB_PRCM_WAKEUP_CLEAR:
|
||||
break;
|
||||
case TUSB_PRCM_WAKEUP_MASK:
|
||||
s->wkup_mask = value;
|
||||
break;
|
||||
|
||||
case TUSB_PULLUP_1_CTRL:
|
||||
s->pullup[0] = value;
|
||||
break;
|
||||
case TUSB_PULLUP_2_CTRL:
|
||||
s->pullup[1] = value;
|
||||
break;
|
||||
case TUSB_INT_CTRL_CONF:
|
||||
s->control_config = value;
|
||||
tusb_intr_update(s);
|
||||
break;
|
||||
|
||||
case TUSB_USBIP_INT_SET:
|
||||
s->usbip_intr |= value;
|
||||
tusb_usbip_intr_update(s);
|
||||
break;
|
||||
case TUSB_USBIP_INT_CLEAR:
|
||||
s->usbip_intr &= ~value;
|
||||
tusb_usbip_intr_update(s);
|
||||
musb_core_intr_clear(s->musb, ~value);
|
||||
break;
|
||||
case TUSB_USBIP_INT_MASK:
|
||||
s->usbip_mask = value;
|
||||
tusb_usbip_intr_update(s);
|
||||
break;
|
||||
|
||||
case TUSB_DMA_INT_SET:
|
||||
s->dma_intr |= value;
|
||||
tusb_dma_intr_update(s);
|
||||
break;
|
||||
case TUSB_DMA_INT_CLEAR:
|
||||
s->dma_intr &= ~value;
|
||||
tusb_dma_intr_update(s);
|
||||
break;
|
||||
case TUSB_DMA_INT_MASK:
|
||||
s->dma_mask = value;
|
||||
tusb_dma_intr_update(s);
|
||||
break;
|
||||
|
||||
case TUSB_GPIO_INT_SET:
|
||||
s->gpio_intr |= value;
|
||||
tusb_gpio_intr_update(s);
|
||||
break;
|
||||
case TUSB_GPIO_INT_CLEAR:
|
||||
s->gpio_intr &= ~value;
|
||||
tusb_gpio_intr_update(s);
|
||||
break;
|
||||
case TUSB_GPIO_INT_MASK:
|
||||
s->gpio_mask = value;
|
||||
tusb_gpio_intr_update(s);
|
||||
break;
|
||||
|
||||
case TUSB_INT_SRC_SET:
|
||||
s->intr |= value;
|
||||
tusb_intr_update(s);
|
||||
break;
|
||||
case TUSB_INT_SRC_CLEAR:
|
||||
s->intr &= ~value;
|
||||
tusb_intr_update(s);
|
||||
break;
|
||||
case TUSB_INT_MASK:
|
||||
s->mask = value;
|
||||
tusb_intr_update(s);
|
||||
break;
|
||||
|
||||
case TUSB_GPIO_CONF:
|
||||
s->gpio_config = value;
|
||||
break;
|
||||
case TUSB_DMA_REQ_CONF:
|
||||
s->dma_config = value;
|
||||
break;
|
||||
case TUSB_EP0_CONF:
|
||||
s->ep0_config = value & 0x1ff;
|
||||
musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
|
||||
value & TUSB_EP0_CONFIG_DIR_TX);
|
||||
break;
|
||||
case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
|
||||
epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
|
||||
s->tx_config[epnum] = value;
|
||||
musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
|
||||
break;
|
||||
case TUSB_DMA_EP_MAP:
|
||||
s->dma_map = value;
|
||||
break;
|
||||
case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
|
||||
epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
|
||||
s->rx_config[epnum] = value;
|
||||
musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
|
||||
break;
|
||||
case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
|
||||
(TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
|
||||
return; /* TODO */
|
||||
case TUSB_WAIT_COUNT:
|
||||
return; /* TODO */
|
||||
|
||||
case TUSB_SCRATCH_PAD:
|
||||
s->scratch = value;
|
||||
break;
|
||||
|
||||
case TUSB_PROD_TEST_RESET:
|
||||
s->test_reset = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: unknown register at %03x\n", __func__, offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t tusb_async_readfn(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return tusb_async_readb(opaque, addr);
|
||||
case 2:
|
||||
return tusb_async_readh(opaque, addr);
|
||||
case 4:
|
||||
return tusb_async_readw(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void tusb_async_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
tusb_async_writeb(opaque, addr, value);
|
||||
break;
|
||||
case 2:
|
||||
tusb_async_writeh(opaque, addr, value);
|
||||
break;
|
||||
case 4:
|
||||
tusb_async_writew(opaque, addr, value);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps tusb_async_ops = {
|
||||
.read = tusb_async_readfn,
|
||||
.write = tusb_async_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void tusb_otg_tick(void *opaque)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
|
||||
s->otg_timer_val = 0;
|
||||
s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
|
||||
tusb_intr_update(s);
|
||||
}
|
||||
|
||||
static void tusb_power_tick(void *opaque)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
|
||||
if (s->power) {
|
||||
s->intr_ok = ~0;
|
||||
tusb_intr_update(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void tusb_musb_core_intr(void *opaque, int source, int level)
|
||||
{
|
||||
TUSBState *s = (TUSBState *) opaque;
|
||||
uint16_t otg_status = s->otg_status;
|
||||
|
||||
switch (source) {
|
||||
case musb_set_vbus:
|
||||
if (level)
|
||||
otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
|
||||
else
|
||||
otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
|
||||
|
||||
/* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set? */
|
||||
/* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set? */
|
||||
if (s->otg_status != otg_status) {
|
||||
s->otg_status = otg_status;
|
||||
s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
|
||||
tusb_intr_update(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case musb_set_session:
|
||||
/* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set? */
|
||||
/* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set? */
|
||||
if (level) {
|
||||
s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
|
||||
s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
|
||||
} else {
|
||||
s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
|
||||
s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
|
||||
}
|
||||
|
||||
/* XXX: some IRQ or anything? */
|
||||
break;
|
||||
|
||||
case musb_irq_tx:
|
||||
case musb_irq_rx:
|
||||
s->usbip_intr = musb_core_intr_get(s->musb);
|
||||
/* Fall through. */
|
||||
default:
|
||||
if (level)
|
||||
s->intr |= 1 << source;
|
||||
else
|
||||
s->intr &= ~(1 << source);
|
||||
tusb_intr_update(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tusb6010_power(TUSBState *s, int on)
|
||||
{
|
||||
if (!on) {
|
||||
s->power = 0;
|
||||
} else if (!s->power && on) {
|
||||
s->power = 1;
|
||||
/* Pull the interrupt down after TUSB6010 comes up. */
|
||||
s->intr_ok = 0;
|
||||
tusb_intr_update(s);
|
||||
timer_mod(s->pwr_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
NANOSECONDS_PER_SECOND / 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void tusb6010_irq(void *opaque, int source, int level)
|
||||
{
|
||||
if (source) {
|
||||
tusb_musb_core_intr(opaque, source - 1, level);
|
||||
} else {
|
||||
tusb6010_power(opaque, level);
|
||||
}
|
||||
}
|
||||
|
||||
static void tusb6010_reset(DeviceState *dev)
|
||||
{
|
||||
TUSBState *s = TUSB6010(dev);
|
||||
int i;
|
||||
|
||||
s->test_reset = TUSB_PROD_TEST_RESET_VAL;
|
||||
s->host_mode = 0;
|
||||
s->dev_config = 0;
|
||||
s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
|
||||
s->power = 0;
|
||||
s->mask = 0xffffffff;
|
||||
s->intr = 0x00000000;
|
||||
s->otg_timer_val = 0;
|
||||
s->scratch = 0;
|
||||
s->prcm_config = 0;
|
||||
s->prcm_mngmt = 0;
|
||||
s->intr_ok = 0;
|
||||
s->usbip_intr = 0;
|
||||
s->usbip_mask = 0;
|
||||
s->gpio_intr = 0;
|
||||
s->gpio_mask = 0;
|
||||
s->gpio_config = 0;
|
||||
s->dma_intr = 0;
|
||||
s->dma_mask = 0;
|
||||
s->dma_map = 0;
|
||||
s->dma_config = 0;
|
||||
s->ep0_config = 0;
|
||||
s->wkup_mask = 0;
|
||||
s->pullup[0] = s->pullup[1] = 0;
|
||||
s->control_config = 0;
|
||||
for (i = 0; i < 15; i++) {
|
||||
s->rx_config[i] = s->tx_config[i] = 0;
|
||||
}
|
||||
musb_reset(s->musb);
|
||||
}
|
||||
|
||||
static void tusb6010_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
TUSBState *s = TUSB6010(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
s->otg_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_otg_tick, s);
|
||||
s->pwr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_power_tick, s);
|
||||
memory_region_init_io(&s->iomem[1], OBJECT(s), &tusb_async_ops, s,
|
||||
"tusb-async", UINT32_MAX);
|
||||
sysbus_init_mmio(sbd, &s->iomem[0]);
|
||||
sysbus_init_mmio(sbd, &s->iomem[1]);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
qdev_init_gpio_in(dev, tusb6010_irq, musb_irq_max + 1);
|
||||
s->musb = musb_init(dev, 1);
|
||||
}
|
||||
|
||||
static void tusb6010_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = tusb6010_realize;
|
||||
device_class_set_legacy_reset(dc, tusb6010_reset);
|
||||
}
|
||||
|
||||
static const TypeInfo tusb6010_info = {
|
||||
.name = TYPE_TUSB6010,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(TUSBState),
|
||||
.class_init = tusb6010_class_init,
|
||||
};
|
||||
|
||||
static void tusb6010_register_types(void)
|
||||
{
|
||||
type_register_static(&tusb6010_info);
|
||||
}
|
||||
|
||||
type_init(tusb6010_register_types)
|
|
@ -21,13 +21,11 @@
|
|||
#define HW_ARM_OMAP_H
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "hw/input/tsc2xxx.h"
|
||||
#include "target/arm/cpu-qom.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
# define OMAP_EMIFS_BASE 0x00000000
|
||||
# define OMAP2_Q0_BASE 0x00000000
|
||||
# define OMAP_CS0_BASE 0x00000000
|
||||
# define OMAP_CS1_BASE 0x04000000
|
||||
# define OMAP_CS2_BASE 0x08000000
|
||||
|
@ -35,20 +33,12 @@
|
|||
# define OMAP_EMIFF_BASE 0x10000000
|
||||
# define OMAP_IMIF_BASE 0x20000000
|
||||
# define OMAP_LOCALBUS_BASE 0x30000000
|
||||
# define OMAP2_Q1_BASE 0x40000000
|
||||
# define OMAP2_L4_BASE 0x48000000
|
||||
# define OMAP2_SRAM_BASE 0x40200000
|
||||
# define OMAP2_L3_BASE 0x68000000
|
||||
# define OMAP2_Q2_BASE 0x80000000
|
||||
# define OMAP2_Q3_BASE 0xc0000000
|
||||
# define OMAP_MPUI_BASE 0xe1000000
|
||||
|
||||
# define OMAP730_SRAM_SIZE 0x00032000
|
||||
# define OMAP15XX_SRAM_SIZE 0x00030000
|
||||
# define OMAP16XX_SRAM_SIZE 0x00004000
|
||||
# define OMAP1611_SRAM_SIZE 0x0003e800
|
||||
# define OMAP242X_SRAM_SIZE 0x000a0000
|
||||
# define OMAP243X_SRAM_SIZE 0x00010000
|
||||
# define OMAP_CS0_SIZE 0x04000000
|
||||
# define OMAP_CS1_SIZE 0x04000000
|
||||
# define OMAP_CS2_SIZE 0x04000000
|
||||
|
@ -106,71 +96,9 @@ typedef struct Omap1GpioState Omap1GpioState;
|
|||
DECLARE_INSTANCE_CHECKER(Omap1GpioState, OMAP1_GPIO,
|
||||
TYPE_OMAP1_GPIO)
|
||||
|
||||
#define TYPE_OMAP2_GPIO "omap2-gpio"
|
||||
typedef struct Omap2GpioState Omap2GpioState;
|
||||
DECLARE_INSTANCE_CHECKER(Omap2GpioState, OMAP2_GPIO,
|
||||
TYPE_OMAP2_GPIO)
|
||||
|
||||
/* TODO: clock framework (see above) */
|
||||
void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk);
|
||||
|
||||
void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk);
|
||||
void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk);
|
||||
|
||||
/* OMAP2 l4 Interconnect */
|
||||
struct omap_l4_s;
|
||||
struct omap_l4_region_s {
|
||||
hwaddr offset;
|
||||
size_t size;
|
||||
int access;
|
||||
};
|
||||
struct omap_l4_agent_info_s {
|
||||
int ta;
|
||||
int region;
|
||||
int regions;
|
||||
int ta_region;
|
||||
};
|
||||
struct omap_target_agent_s {
|
||||
MemoryRegion iomem;
|
||||
struct omap_l4_s *bus;
|
||||
int regions;
|
||||
const struct omap_l4_region_s *start;
|
||||
hwaddr base;
|
||||
uint32_t component;
|
||||
uint32_t control;
|
||||
uint32_t status;
|
||||
};
|
||||
struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
|
||||
hwaddr base, int ta_num);
|
||||
|
||||
struct omap_target_agent_s;
|
||||
struct omap_target_agent_s *omap_l4ta_get(
|
||||
struct omap_l4_s *bus,
|
||||
const struct omap_l4_region_s *regions,
|
||||
const struct omap_l4_agent_info_s *agents,
|
||||
int cs);
|
||||
hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
|
||||
int region, MemoryRegion *mr);
|
||||
hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
|
||||
int region);
|
||||
hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
|
||||
int region);
|
||||
|
||||
/* OMAP2 SDRAM controller */
|
||||
struct omap_sdrc_s;
|
||||
struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
|
||||
hwaddr base);
|
||||
void omap_sdrc_reset(struct omap_sdrc_s *s);
|
||||
|
||||
/* OMAP2 general purpose memory controller */
|
||||
struct omap_gpmc_s;
|
||||
struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
|
||||
hwaddr base,
|
||||
qemu_irq irq, qemu_irq drq);
|
||||
void omap_gpmc_reset(struct omap_gpmc_s *s);
|
||||
void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem);
|
||||
void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand);
|
||||
|
||||
/*
|
||||
* Common IRQ numbers for level 1 interrupt handler
|
||||
* See /usr/include/asm-arm/arch-omap/irqs.h in Linux.
|
||||
|
@ -398,93 +326,11 @@ void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand);
|
|||
# define OMAP_INT_730_DMA_CH15 62
|
||||
# define OMAP_INT_730_NAND 63
|
||||
|
||||
/*
|
||||
* OMAP-24xx common IRQ numbers
|
||||
*/
|
||||
# define OMAP_INT_24XX_STI 4
|
||||
# define OMAP_INT_24XX_SYS_NIRQ 7
|
||||
# define OMAP_INT_24XX_L3_IRQ 10
|
||||
# define OMAP_INT_24XX_PRCM_MPU_IRQ 11
|
||||
# define OMAP_INT_24XX_SDMA_IRQ0 12
|
||||
# define OMAP_INT_24XX_SDMA_IRQ1 13
|
||||
# define OMAP_INT_24XX_SDMA_IRQ2 14
|
||||
# define OMAP_INT_24XX_SDMA_IRQ3 15
|
||||
# define OMAP_INT_243X_MCBSP2_IRQ 16
|
||||
# define OMAP_INT_243X_MCBSP3_IRQ 17
|
||||
# define OMAP_INT_243X_MCBSP4_IRQ 18
|
||||
# define OMAP_INT_243X_MCBSP5_IRQ 19
|
||||
# define OMAP_INT_24XX_GPMC_IRQ 20
|
||||
# define OMAP_INT_24XX_GUFFAW_IRQ 21
|
||||
# define OMAP_INT_24XX_IVA_IRQ 22
|
||||
# define OMAP_INT_24XX_EAC_IRQ 23
|
||||
# define OMAP_INT_24XX_CAM_IRQ 24
|
||||
# define OMAP_INT_24XX_DSS_IRQ 25
|
||||
# define OMAP_INT_24XX_MAIL_U0_MPU 26
|
||||
# define OMAP_INT_24XX_DSP_UMA 27
|
||||
# define OMAP_INT_24XX_DSP_MMU 28
|
||||
# define OMAP_INT_24XX_GPIO_BANK1 29
|
||||
# define OMAP_INT_24XX_GPIO_BANK2 30
|
||||
# define OMAP_INT_24XX_GPIO_BANK3 31
|
||||
# define OMAP_INT_24XX_GPIO_BANK4 32
|
||||
# define OMAP_INT_243X_GPIO_BANK5 33
|
||||
# define OMAP_INT_24XX_MAIL_U3_MPU 34
|
||||
# define OMAP_INT_24XX_WDT3 35
|
||||
# define OMAP_INT_24XX_WDT4 36
|
||||
# define OMAP_INT_24XX_GPTIMER1 37
|
||||
# define OMAP_INT_24XX_GPTIMER2 38
|
||||
# define OMAP_INT_24XX_GPTIMER3 39
|
||||
# define OMAP_INT_24XX_GPTIMER4 40
|
||||
# define OMAP_INT_24XX_GPTIMER5 41
|
||||
# define OMAP_INT_24XX_GPTIMER6 42
|
||||
# define OMAP_INT_24XX_GPTIMER7 43
|
||||
# define OMAP_INT_24XX_GPTIMER8 44
|
||||
# define OMAP_INT_24XX_GPTIMER9 45
|
||||
# define OMAP_INT_24XX_GPTIMER10 46
|
||||
# define OMAP_INT_24XX_GPTIMER11 47
|
||||
# define OMAP_INT_24XX_GPTIMER12 48
|
||||
# define OMAP_INT_24XX_PKA_IRQ 50
|
||||
# define OMAP_INT_24XX_SHA1MD5_IRQ 51
|
||||
# define OMAP_INT_24XX_RNG_IRQ 52
|
||||
# define OMAP_INT_24XX_MG_IRQ 53
|
||||
# define OMAP_INT_24XX_I2C1_IRQ 56
|
||||
# define OMAP_INT_24XX_I2C2_IRQ 57
|
||||
# define OMAP_INT_24XX_MCBSP1_IRQ_TX 59
|
||||
# define OMAP_INT_24XX_MCBSP1_IRQ_RX 60
|
||||
# define OMAP_INT_24XX_MCBSP2_IRQ_TX 62
|
||||
# define OMAP_INT_24XX_MCBSP2_IRQ_RX 63
|
||||
# define OMAP_INT_243X_MCBSP1_IRQ 64
|
||||
# define OMAP_INT_24XX_MCSPI1_IRQ 65
|
||||
# define OMAP_INT_24XX_MCSPI2_IRQ 66
|
||||
# define OMAP_INT_24XX_SSI1_IRQ0 67
|
||||
# define OMAP_INT_24XX_SSI1_IRQ1 68
|
||||
# define OMAP_INT_24XX_SSI2_IRQ0 69
|
||||
# define OMAP_INT_24XX_SSI2_IRQ1 70
|
||||
# define OMAP_INT_24XX_SSI_GDD_IRQ 71
|
||||
# define OMAP_INT_24XX_UART1_IRQ 72
|
||||
# define OMAP_INT_24XX_UART2_IRQ 73
|
||||
# define OMAP_INT_24XX_UART3_IRQ 74
|
||||
# define OMAP_INT_24XX_USB_IRQ_GEN 75
|
||||
# define OMAP_INT_24XX_USB_IRQ_NISO 76
|
||||
# define OMAP_INT_24XX_USB_IRQ_ISO 77
|
||||
# define OMAP_INT_24XX_USB_IRQ_HGEN 78
|
||||
# define OMAP_INT_24XX_USB_IRQ_HSOF 79
|
||||
# define OMAP_INT_24XX_USB_IRQ_OTG 80
|
||||
# define OMAP_INT_24XX_VLYNQ_IRQ 81
|
||||
# define OMAP_INT_24XX_MMC_IRQ 83
|
||||
# define OMAP_INT_24XX_MS_IRQ 84
|
||||
# define OMAP_INT_24XX_FAC_IRQ 85
|
||||
# define OMAP_INT_24XX_MCSPI3_IRQ 91
|
||||
# define OMAP_INT_243X_HS_USB_MC 92
|
||||
# define OMAP_INT_243X_HS_USB_DMA 93
|
||||
# define OMAP_INT_243X_CARKIT 94
|
||||
# define OMAP_INT_34XX_GPTIMER12 95
|
||||
|
||||
/* omap_dma.c */
|
||||
enum omap_dma_model {
|
||||
omap_dma_3_0,
|
||||
omap_dma_3_1,
|
||||
omap_dma_3_2,
|
||||
omap_dma_4,
|
||||
};
|
||||
|
||||
struct soc_dma_s;
|
||||
|
@ -632,97 +478,11 @@ struct omap_dma_lcd_channel_s {
|
|||
# define OMAP_DMA_MMC2_RX 55
|
||||
# define OMAP_DMA_CRYPTO_DES_OUT 56
|
||||
|
||||
/*
|
||||
* DMA request numbers for the OMAP2
|
||||
*/
|
||||
# define OMAP24XX_DMA_NO_DEVICE 0
|
||||
# define OMAP24XX_DMA_XTI_DMA 1 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_EXT_DMAREQ0 2
|
||||
# define OMAP24XX_DMA_EXT_DMAREQ1 3
|
||||
# define OMAP24XX_DMA_GPMC 4
|
||||
# define OMAP24XX_DMA_GFX 5 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_DSS 6
|
||||
# define OMAP24XX_DMA_VLYNQ_TX 7 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_CWT 8 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_AES_TX 9 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_AES_RX 10 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_DES_TX 11 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_DES_RX 12 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_SHA1MD5_RX 13 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_EXT_DMAREQ2 14
|
||||
# define OMAP24XX_DMA_EXT_DMAREQ3 15
|
||||
# define OMAP24XX_DMA_EXT_DMAREQ4 16
|
||||
# define OMAP24XX_DMA_EAC_AC_RD 17
|
||||
# define OMAP24XX_DMA_EAC_AC_WR 18
|
||||
# define OMAP24XX_DMA_EAC_MD_UL_RD 19
|
||||
# define OMAP24XX_DMA_EAC_MD_UL_WR 20
|
||||
# define OMAP24XX_DMA_EAC_MD_DL_RD 21
|
||||
# define OMAP24XX_DMA_EAC_MD_DL_WR 22
|
||||
# define OMAP24XX_DMA_EAC_BT_UL_RD 23
|
||||
# define OMAP24XX_DMA_EAC_BT_UL_WR 24
|
||||
# define OMAP24XX_DMA_EAC_BT_DL_RD 25
|
||||
# define OMAP24XX_DMA_EAC_BT_DL_WR 26
|
||||
# define OMAP24XX_DMA_I2C1_TX 27
|
||||
# define OMAP24XX_DMA_I2C1_RX 28
|
||||
# define OMAP24XX_DMA_I2C2_TX 29
|
||||
# define OMAP24XX_DMA_I2C2_RX 30
|
||||
# define OMAP24XX_DMA_MCBSP1_TX 31
|
||||
# define OMAP24XX_DMA_MCBSP1_RX 32
|
||||
# define OMAP24XX_DMA_MCBSP2_TX 33
|
||||
# define OMAP24XX_DMA_MCBSP2_RX 34
|
||||
# define OMAP24XX_DMA_SPI1_TX0 35
|
||||
# define OMAP24XX_DMA_SPI1_RX0 36
|
||||
# define OMAP24XX_DMA_SPI1_TX1 37
|
||||
# define OMAP24XX_DMA_SPI1_RX1 38
|
||||
# define OMAP24XX_DMA_SPI1_TX2 39
|
||||
# define OMAP24XX_DMA_SPI1_RX2 40
|
||||
# define OMAP24XX_DMA_SPI1_TX3 41
|
||||
# define OMAP24XX_DMA_SPI1_RX3 42
|
||||
# define OMAP24XX_DMA_SPI2_TX0 43
|
||||
# define OMAP24XX_DMA_SPI2_RX0 44
|
||||
# define OMAP24XX_DMA_SPI2_TX1 45
|
||||
# define OMAP24XX_DMA_SPI2_RX1 46
|
||||
|
||||
# define OMAP24XX_DMA_UART1_TX 49
|
||||
# define OMAP24XX_DMA_UART1_RX 50
|
||||
# define OMAP24XX_DMA_UART2_TX 51
|
||||
# define OMAP24XX_DMA_UART2_RX 52
|
||||
# define OMAP24XX_DMA_UART3_TX 53
|
||||
# define OMAP24XX_DMA_UART3_RX 54
|
||||
# define OMAP24XX_DMA_USB_W2FC_TX0 55
|
||||
# define OMAP24XX_DMA_USB_W2FC_RX0 56
|
||||
# define OMAP24XX_DMA_USB_W2FC_TX1 57
|
||||
# define OMAP24XX_DMA_USB_W2FC_RX1 58
|
||||
# define OMAP24XX_DMA_USB_W2FC_TX2 59
|
||||
# define OMAP24XX_DMA_USB_W2FC_RX2 60
|
||||
# define OMAP24XX_DMA_MMC1_TX 61
|
||||
# define OMAP24XX_DMA_MMC1_RX 62
|
||||
# define OMAP24XX_DMA_MS 63 /* Not in OMAP2420 */
|
||||
# define OMAP24XX_DMA_EXT_DMAREQ5 64
|
||||
|
||||
/* omap[123].c */
|
||||
/* OMAP2 gp timer */
|
||||
struct omap_gp_timer_s;
|
||||
struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
|
||||
qemu_irq irq, omap_clk fclk, omap_clk iclk);
|
||||
void omap_gp_timer_reset(struct omap_gp_timer_s *s);
|
||||
|
||||
/* OMAP2 sysctimer */
|
||||
struct omap_synctimer_s;
|
||||
struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
|
||||
struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk);
|
||||
void omap_synctimer_reset(struct omap_synctimer_s *s);
|
||||
|
||||
struct omap_uart_s;
|
||||
struct omap_uart_s *omap_uart_init(hwaddr base,
|
||||
qemu_irq irq, omap_clk fclk, omap_clk iclk,
|
||||
qemu_irq txdma, qemu_irq rxdma,
|
||||
const char *label, Chardev *chr);
|
||||
struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
|
||||
struct omap_target_agent_s *ta,
|
||||
qemu_irq irq, omap_clk fclk, omap_clk iclk,
|
||||
qemu_irq txdma, qemu_irq rxdma,
|
||||
const char *label, Chardev *chr);
|
||||
void omap_uart_reset(struct omap_uart_s *s);
|
||||
|
||||
struct omap_mpuio_s;
|
||||
|
@ -730,19 +490,16 @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
|
|||
void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
|
||||
void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
|
||||
|
||||
typedef struct uWireSlave {
|
||||
uint16_t (*receive)(void *opaque);
|
||||
void (*send)(void *opaque, uint16_t data);
|
||||
void *opaque;
|
||||
} uWireSlave;
|
||||
|
||||
struct omap_uwire_s;
|
||||
void omap_uwire_attach(struct omap_uwire_s *s,
|
||||
uWireSlave *slave, int chipselect);
|
||||
|
||||
/* OMAP2 spi */
|
||||
struct omap_mcspi_s;
|
||||
struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
|
||||
qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk);
|
||||
void omap_mcspi_attach(struct omap_mcspi_s *s,
|
||||
uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
|
||||
int chipselect);
|
||||
void omap_mcspi_reset(struct omap_mcspi_s *s);
|
||||
|
||||
struct I2SCodec {
|
||||
void *opaque;
|
||||
|
||||
|
@ -770,9 +527,6 @@ struct I2SCodec {
|
|||
struct omap_mcbsp_s;
|
||||
void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
|
||||
|
||||
void omap_tap_init(struct omap_target_agent_s *ta,
|
||||
struct omap_mpu_state_s *mpu);
|
||||
|
||||
/* omap_lcdc.c */
|
||||
struct omap_lcd_panel_s;
|
||||
void omap_lcdc_reset(struct omap_lcd_panel_s *s);
|
||||
|
@ -782,35 +536,13 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
|
|||
struct omap_dma_lcd_channel_s *dma,
|
||||
omap_clk clk);
|
||||
|
||||
/* omap_dss.c */
|
||||
struct rfbi_chip_s {
|
||||
void *opaque;
|
||||
void (*write)(void *opaque, int dc, uint16_t value);
|
||||
void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch);
|
||||
uint16_t (*read)(void *opaque, int dc);
|
||||
};
|
||||
struct omap_dss_s;
|
||||
void omap_dss_reset(struct omap_dss_s *s);
|
||||
struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
|
||||
MemoryRegion *sysmem,
|
||||
hwaddr l3_base,
|
||||
qemu_irq irq, qemu_irq drq,
|
||||
omap_clk fck1, omap_clk fck2, omap_clk ck54m,
|
||||
omap_clk ick1, omap_clk ick2);
|
||||
void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip);
|
||||
|
||||
/* omap_mmc.c */
|
||||
struct omap_mmc_s;
|
||||
struct omap_mmc_s *omap_mmc_init(hwaddr base,
|
||||
MemoryRegion *sysmem,
|
||||
BlockBackend *blk,
|
||||
qemu_irq irq, qemu_irq dma[], omap_clk clk);
|
||||
struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
|
||||
BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
|
||||
omap_clk fclk, omap_clk iclk);
|
||||
void omap_mmc_reset(struct omap_mmc_s *s);
|
||||
void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
|
||||
void omap_mmc_enable(struct omap_mmc_s *s, int enable);
|
||||
|
||||
/* omap_i2c.c */
|
||||
I2CBus *omap_i2c_bus(DeviceState *omap_i2c);
|
||||
|
@ -819,24 +551,11 @@ I2CBus *omap_i2c_bus(DeviceState *omap_i2c);
|
|||
# define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510)
|
||||
# define cpu_is_omap1610(cpu) (cpu->mpu_model == omap1610)
|
||||
# define cpu_is_omap1710(cpu) (cpu->mpu_model == omap1710)
|
||||
# define cpu_is_omap2410(cpu) (cpu->mpu_model == omap2410)
|
||||
# define cpu_is_omap2420(cpu) (cpu->mpu_model == omap2420)
|
||||
# define cpu_is_omap2430(cpu) (cpu->mpu_model == omap2430)
|
||||
# define cpu_is_omap3430(cpu) (cpu->mpu_model == omap3430)
|
||||
# define cpu_is_omap3630(cpu) (cpu->mpu_model == omap3630)
|
||||
|
||||
# define cpu_is_omap15xx(cpu) \
|
||||
(cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
|
||||
# define cpu_is_omap16xx(cpu) \
|
||||
(cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu))
|
||||
# define cpu_is_omap24xx(cpu) \
|
||||
(cpu_is_omap2410(cpu) || cpu_is_omap2420(cpu) || cpu_is_omap2430(cpu))
|
||||
|
||||
# define cpu_class_omap1(cpu) \
|
||||
(cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu))
|
||||
# define cpu_class_omap2(cpu) cpu_is_omap24xx(cpu)
|
||||
# define cpu_class_omap3(cpu) \
|
||||
(cpu_is_omap3430(cpu) || cpu_is_omap3630(cpu))
|
||||
|
||||
struct omap_mpu_state_s {
|
||||
enum omap_mpu_model {
|
||||
|
@ -844,13 +563,6 @@ struct omap_mpu_state_s {
|
|||
omap1510,
|
||||
omap1610,
|
||||
omap1710,
|
||||
omap2410,
|
||||
omap2420,
|
||||
omap2422,
|
||||
omap2423,
|
||||
omap2430,
|
||||
omap3430,
|
||||
omap3630,
|
||||
} mpu_model;
|
||||
|
||||
ARMCPU *cpu;
|
||||
|
@ -960,33 +672,12 @@ struct omap_mpu_state_s {
|
|||
uint16_t dsp_idlect2;
|
||||
uint16_t dsp_rstct2;
|
||||
} clkm;
|
||||
|
||||
/* OMAP2-only peripherals */
|
||||
struct omap_l4_s *l4;
|
||||
|
||||
struct omap_gp_timer_s *gptimer[12];
|
||||
struct omap_synctimer_s *synctimer;
|
||||
|
||||
struct omap_prcm_s *prcm;
|
||||
struct omap_sdrc_s *sdrc;
|
||||
struct omap_gpmc_s *gpmc;
|
||||
struct omap_sysctl_s *sysc;
|
||||
|
||||
struct omap_mcspi_s *mcspi[2];
|
||||
|
||||
struct omap_dss_s *dss;
|
||||
|
||||
struct omap_eac_s *eac;
|
||||
};
|
||||
|
||||
/* omap1.c */
|
||||
struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *sdram,
|
||||
const char *core);
|
||||
|
||||
/* omap2.c */
|
||||
struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram,
|
||||
const char *core);
|
||||
|
||||
uint32_t omap_badwidth_read8(void *opaque, hwaddr addr);
|
||||
void omap_badwidth_write8(void *opaque, hwaddr addr,
|
||||
uint32_t value);
|
||||
|
@ -1007,35 +698,6 @@ void omap_mpu_wakeup(void *opaque, int irq, int req);
|
|||
HWADDR_PRIx "\n", \
|
||||
__func__, paddr)
|
||||
|
||||
/* OMAP-specific Linux bootloader tags for the ATAG_BOARD area
|
||||
* (Board-specific tags are not here)
|
||||
*/
|
||||
#define OMAP_TAG_CLOCK 0x4f01
|
||||
#define OMAP_TAG_MMC 0x4f02
|
||||
#define OMAP_TAG_SERIAL_CONSOLE 0x4f03
|
||||
#define OMAP_TAG_USB 0x4f04
|
||||
#define OMAP_TAG_LCD 0x4f05
|
||||
#define OMAP_TAG_GPIO_SWITCH 0x4f06
|
||||
#define OMAP_TAG_UART 0x4f07
|
||||
#define OMAP_TAG_FBMEM 0x4f08
|
||||
#define OMAP_TAG_STI_CONSOLE 0x4f09
|
||||
#define OMAP_TAG_CAMERA_SENSOR 0x4f0a
|
||||
#define OMAP_TAG_PARTITION 0x4f0b
|
||||
#define OMAP_TAG_TEA5761 0x4f10
|
||||
#define OMAP_TAG_TMP105 0x4f11
|
||||
#define OMAP_TAG_BOOT_REASON 0x4f80
|
||||
#define OMAP_TAG_FLASH_PART_STR 0x4f81
|
||||
#define OMAP_TAG_VERSION_STR 0x4f82
|
||||
|
||||
enum {
|
||||
OMAP_GPIOSW_TYPE_COVER = 0 << 4,
|
||||
OMAP_GPIOSW_TYPE_CONNECTION = 1 << 4,
|
||||
OMAP_GPIOSW_TYPE_ACTIVITY = 2 << 4,
|
||||
};
|
||||
|
||||
#define OMAP_GPIOSW_INVERTED 0x0001
|
||||
#define OMAP_GPIOSW_OUTPUT 0x0002
|
||||
|
||||
# define OMAP_MPUI_REG_MASK 0x000007ff
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
* Intel XScale PXA255/270 processor support.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*/
|
||||
|
||||
#ifndef PXA_H
|
||||
#define PXA_H
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "target/arm/cpu-qom.h"
|
||||
#include "hw/pcmcia.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* Interrupt numbers */
|
||||
# define PXA2XX_PIC_SSP3 0
|
||||
# define PXA2XX_PIC_USBH2 2
|
||||
# define PXA2XX_PIC_USBH1 3
|
||||
# define PXA2XX_PIC_KEYPAD 4
|
||||
# define PXA2XX_PIC_PWRI2C 6
|
||||
# define PXA25X_PIC_HWUART 7
|
||||
# define PXA27X_PIC_OST_4_11 7
|
||||
# define PXA2XX_PIC_GPIO_0 8
|
||||
# define PXA2XX_PIC_GPIO_1 9
|
||||
# define PXA2XX_PIC_GPIO_X 10
|
||||
# define PXA2XX_PIC_I2S 13
|
||||
# define PXA26X_PIC_ASSP 15
|
||||
# define PXA25X_PIC_NSSP 16
|
||||
# define PXA27X_PIC_SSP2 16
|
||||
# define PXA2XX_PIC_LCD 17
|
||||
# define PXA2XX_PIC_I2C 18
|
||||
# define PXA2XX_PIC_ICP 19
|
||||
# define PXA2XX_PIC_STUART 20
|
||||
# define PXA2XX_PIC_BTUART 21
|
||||
# define PXA2XX_PIC_FFUART 22
|
||||
# define PXA2XX_PIC_MMC 23
|
||||
# define PXA2XX_PIC_SSP 24
|
||||
# define PXA2XX_PIC_DMA 25
|
||||
# define PXA2XX_PIC_OST_0 26
|
||||
# define PXA2XX_PIC_RTC1HZ 30
|
||||
# define PXA2XX_PIC_RTCALARM 31
|
||||
|
||||
/* DMA requests */
|
||||
# define PXA2XX_RX_RQ_I2S 2
|
||||
# define PXA2XX_TX_RQ_I2S 3
|
||||
# define PXA2XX_RX_RQ_BTUART 4
|
||||
# define PXA2XX_TX_RQ_BTUART 5
|
||||
# define PXA2XX_RX_RQ_FFUART 6
|
||||
# define PXA2XX_TX_RQ_FFUART 7
|
||||
# define PXA2XX_RX_RQ_SSP1 13
|
||||
# define PXA2XX_TX_RQ_SSP1 14
|
||||
# define PXA2XX_RX_RQ_SSP2 15
|
||||
# define PXA2XX_TX_RQ_SSP2 16
|
||||
# define PXA2XX_RX_RQ_ICP 17
|
||||
# define PXA2XX_TX_RQ_ICP 18
|
||||
# define PXA2XX_RX_RQ_STUART 19
|
||||
# define PXA2XX_TX_RQ_STUART 20
|
||||
# define PXA2XX_RX_RQ_MMCI 21
|
||||
# define PXA2XX_TX_RQ_MMCI 22
|
||||
# define PXA2XX_USB_RQ(x) ((x) + 24)
|
||||
# define PXA2XX_RX_RQ_SSP3 66
|
||||
# define PXA2XX_TX_RQ_SSP3 67
|
||||
|
||||
# define PXA2XX_SDRAM_BASE 0xa0000000
|
||||
# define PXA2XX_INTERNAL_BASE 0x5c000000
|
||||
# define PXA2XX_INTERNAL_SIZE 0x40000
|
||||
|
||||
/* pxa2xx_pic.c */
|
||||
DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu);
|
||||
|
||||
/* pxa2xx_gpio.c */
|
||||
DeviceState *pxa2xx_gpio_init(hwaddr base,
|
||||
ARMCPU *cpu, DeviceState *pic, int lines);
|
||||
void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler);
|
||||
|
||||
/* pxa2xx_dma.c */
|
||||
DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq);
|
||||
DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq);
|
||||
|
||||
/* pxa2xx_lcd.c */
|
||||
typedef struct PXA2xxLCDState PXA2xxLCDState;
|
||||
PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
|
||||
hwaddr base, qemu_irq irq);
|
||||
void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler);
|
||||
|
||||
/* pxa2xx_mmci.c */
|
||||
#define TYPE_PXA2XX_MMCI "pxa2xx-mmci"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxMMCIState, PXA2XX_MMCI)
|
||||
|
||||
PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
|
||||
hwaddr base,
|
||||
qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma);
|
||||
void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
|
||||
qemu_irq coverswitch);
|
||||
|
||||
/* pxa2xx_pcmcia.c */
|
||||
#define TYPE_PXA2XX_PCMCIA "pxa2xx-pcmcia"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxPCMCIAState, PXA2XX_PCMCIA)
|
||||
|
||||
int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card);
|
||||
int pxa2xx_pcmcia_detach(void *opaque);
|
||||
void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq);
|
||||
|
||||
/* pxa2xx_keypad.c */
|
||||
struct keymap {
|
||||
int8_t column;
|
||||
int8_t row;
|
||||
};
|
||||
typedef struct PXA2xxKeyPadState PXA2xxKeyPadState;
|
||||
PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
|
||||
hwaddr base,
|
||||
qemu_irq irq);
|
||||
void pxa27x_register_keypad(PXA2xxKeyPadState *kp,
|
||||
const struct keymap *map, int size);
|
||||
|
||||
/* pxa2xx.c */
|
||||
#define TYPE_PXA2XX_I2C "pxa2xx_i2c"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxI2CState, PXA2XX_I2C)
|
||||
|
||||
PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
|
||||
qemu_irq irq, uint32_t page_size);
|
||||
I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s);
|
||||
|
||||
typedef struct PXA2xxI2SState PXA2xxI2SState;
|
||||
|
||||
#define TYPE_PXA2XX_FIR "pxa2xx-fir"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxFIrState, PXA2XX_FIR)
|
||||
|
||||
typedef struct {
|
||||
ARMCPU *cpu;
|
||||
DeviceState *pic;
|
||||
qemu_irq reset;
|
||||
MemoryRegion sdram;
|
||||
MemoryRegion internal;
|
||||
MemoryRegion cm_iomem;
|
||||
MemoryRegion mm_iomem;
|
||||
MemoryRegion pm_iomem;
|
||||
DeviceState *dma;
|
||||
DeviceState *gpio;
|
||||
PXA2xxLCDState *lcd;
|
||||
SSIBus **ssp;
|
||||
PXA2xxI2CState *i2c[2];
|
||||
PXA2xxMMCIState *mmc;
|
||||
PXA2xxPCMCIAState *pcmcia[2];
|
||||
PXA2xxI2SState *i2s;
|
||||
PXA2xxFIrState *fir;
|
||||
PXA2xxKeyPadState *kp;
|
||||
|
||||
/* Power management */
|
||||
hwaddr pm_base;
|
||||
uint32_t pm_regs[0x40];
|
||||
|
||||
/* Clock management */
|
||||
hwaddr cm_base;
|
||||
uint32_t cm_regs[4];
|
||||
uint32_t clkcfg;
|
||||
|
||||
/* Memory management */
|
||||
hwaddr mm_base;
|
||||
uint32_t mm_regs[0x1a];
|
||||
|
||||
/* Performance monitoring */
|
||||
uint32_t pmnc;
|
||||
} PXA2xxState;
|
||||
|
||||
struct PXA2xxI2SState {
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
qemu_irq rx_dma;
|
||||
qemu_irq tx_dma;
|
||||
void (*data_req)(void *, int, int);
|
||||
|
||||
uint32_t control[2];
|
||||
uint32_t status;
|
||||
uint32_t mask;
|
||||
uint32_t clk;
|
||||
|
||||
int enable;
|
||||
int rx_len;
|
||||
int tx_len;
|
||||
void (*codec_out)(void *, uint32_t);
|
||||
uint32_t (*codec_in)(void *);
|
||||
void *opaque;
|
||||
|
||||
int fifo_len;
|
||||
uint32_t fifo[16];
|
||||
};
|
||||
|
||||
# define PA_FMT "0x%08lx"
|
||||
|
||||
PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision);
|
||||
PXA2xxState *pxa255_init(unsigned int sdram_size);
|
||||
|
||||
#endif /* PXA_H */
|
|
@ -78,6 +78,7 @@ struct Versal {
|
|||
struct {
|
||||
PL011State uart[XLNX_VERSAL_NR_UARTS];
|
||||
CadenceGEMState gem[XLNX_VERSAL_NR_GEMS];
|
||||
OrIRQState gem_irq_orgate[XLNX_VERSAL_NR_GEMS];
|
||||
XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS];
|
||||
VersalUsb2 usb;
|
||||
CanBusState *canbus[XLNX_VERSAL_NR_CANFD];
|
||||
|
|
|
@ -116,6 +116,7 @@ struct XlnxZynqMPState {
|
|||
MemoryRegion mr_unimp[XLNX_ZYNQMP_NUM_UNIMP_AREAS];
|
||||
|
||||
CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
|
||||
OrIRQState gem_irq_orgate[XLNX_ZYNQMP_NUM_GEMS];
|
||||
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
|
||||
XlnxZynqMPCANState can[XLNX_ZYNQMP_NUM_CAN];
|
||||
SysbusAHCIState sata;
|
||||
|
|
|
@ -62,9 +62,6 @@ uint32_t nand_getbuswidth(DeviceState *dev);
|
|||
#define NAND_MFR_HYNIX 0xad
|
||||
#define NAND_MFR_MICRON 0x2c
|
||||
|
||||
/* onenand.c */
|
||||
void *onenand_raw_otp(DeviceState *onenand_device);
|
||||
|
||||
/* ecc.c */
|
||||
typedef struct {
|
||||
uint8_t cp; /* Column parity */
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_DISPLAY_BLIZZARD_H
|
||||
#define HW_DISPLAY_BLIZZARD_H
|
||||
|
||||
|
||||
void *s1d13745_init(qemu_irq gpio_int);
|
||||
void s1d13745_write(void *opaque, int dc, uint16_t value);
|
||||
void s1d13745_write_block(void *opaque, int dc,
|
||||
void *buf, size_t len, int pitch);
|
||||
uint16_t s1d13745_read(void *opaque, int dc);
|
||||
|
||||
#endif
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Toshiba TC6393XB I/O Controller.
|
||||
* Found in Sharp Zaurus SL-6000 (tosa) or some
|
||||
* Toshiba e-Series PDAs.
|
||||
*
|
||||
* Copyright (c) 2007 Hervé Poussineau
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_DISPLAY_TC6393XB_H
|
||||
#define HW_DISPLAY_TC6393XB_H
|
||||
|
||||
typedef struct TC6393xbState TC6393xbState;
|
||||
|
||||
TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
|
||||
uint32_t base, qemu_irq irq);
|
||||
qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
|
||||
|
||||
#endif
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_INPUT_LM832X_H
|
||||
#define HW_INPUT_LM832X_H
|
||||
|
||||
#define TYPE_LM8323 "lm8323"
|
||||
|
||||
void lm832x_key_event(DeviceState *dev, int key, int state);
|
||||
|
||||
#endif
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* TI touchscreen controller
|
||||
*
|
||||
* Copyright (c) 2006 Andrzej Zaborowski
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_INPUT_TSC2XXX_H
|
||||
#define HW_INPUT_TSC2XXX_H
|
||||
|
||||
typedef struct MouseTransformInfo {
|
||||
/* Touchscreen resolution */
|
||||
int x;
|
||||
int y;
|
||||
/* Calibration values as used/generated by tslib */
|
||||
int a[7];
|
||||
} MouseTransformInfo;
|
||||
|
||||
typedef struct uWireSlave {
|
||||
uint16_t (*receive)(void *opaque);
|
||||
void (*send)(void *opaque, uint16_t data);
|
||||
void *opaque;
|
||||
} uWireSlave;
|
||||
|
||||
/* tsc210x.c */
|
||||
uWireSlave *tsc2102_init(qemu_irq pint);
|
||||
uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
|
||||
I2SCodec *tsc210x_codec(uWireSlave *chip);
|
||||
uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
|
||||
void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info);
|
||||
void tsc210x_key_event(uWireSlave *chip, int key, int down);
|
||||
|
||||
/* tsc2005.c */
|
||||
void *tsc2005_init(qemu_irq pintdav);
|
||||
uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
|
||||
void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info);
|
||||
|
||||
#endif
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
|
||||
* Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
|
||||
* Based on reverse-engineering of a linux driver.
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_MISC_CBUS_H
|
||||
#define HW_MISC_CBUS_H
|
||||
|
||||
|
||||
typedef struct {
|
||||
qemu_irq clk;
|
||||
qemu_irq dat;
|
||||
qemu_irq sel;
|
||||
} CBus;
|
||||
|
||||
CBus *cbus_init(qemu_irq dat_out);
|
||||
void cbus_attach(CBus *bus, void *slave_opaque);
|
||||
|
||||
void *retu_init(qemu_irq irq, int vilma);
|
||||
void *tahvo_init(qemu_irq irq, int betty);
|
||||
|
||||
void retu_key_event(void *retu, int state);
|
||||
|
||||
#endif
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics,
|
||||
* USB2.0 OTG compliant core used in various chips.
|
||||
*
|
||||
* Only host-mode and non-DMA accesses are currently supported.
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_USB_HCD_MUSB_H
|
||||
#define HW_USB_HCD_MUSB_H
|
||||
|
||||
#include "exec/hwaddr.h"
|
||||
|
||||
enum musb_irq_source_e {
|
||||
musb_irq_suspend = 0,
|
||||
musb_irq_resume,
|
||||
musb_irq_rst_babble,
|
||||
musb_irq_sof,
|
||||
musb_irq_connect,
|
||||
musb_irq_disconnect,
|
||||
musb_irq_vbus_request,
|
||||
musb_irq_vbus_error,
|
||||
musb_irq_rx,
|
||||
musb_irq_tx,
|
||||
musb_set_vbus,
|
||||
musb_set_session,
|
||||
/* Add new interrupts here */
|
||||
musb_irq_max /* total number of interrupts defined */
|
||||
};
|
||||
|
||||
/* TODO convert hcd-musb to QOM/qdev and remove MUSBReadFunc/MUSBWriteFunc */
|
||||
typedef void MUSBWriteFunc(void *opaque, hwaddr addr, uint32_t value);
|
||||
typedef uint32_t MUSBReadFunc(void *opaque, hwaddr addr);
|
||||
extern MUSBReadFunc * const musb_read[];
|
||||
extern MUSBWriteFunc * const musb_write[];
|
||||
|
||||
typedef struct MUSBState MUSBState;
|
||||
|
||||
MUSBState *musb_init(DeviceState *parent_device, int gpio_base);
|
||||
void musb_reset(MUSBState *s);
|
||||
uint32_t musb_core_intr_get(MUSBState *s);
|
||||
void musb_core_intr_clear(MUSBState *s, uint32_t mask);
|
||||
void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
|
||||
|
||||
#endif
|
|
@ -1449,7 +1449,7 @@ typedef struct GetPhysAddrResult {
|
|||
* * for PSMAv5 based systems we don't bother to return a full FSR format
|
||||
* value.
|
||||
*/
|
||||
bool get_phys_addr(CPUARMState *env, target_ulong address,
|
||||
bool get_phys_addr(CPUARMState *env, vaddr address,
|
||||
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
||||
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
|
||||
__attribute__((nonnull));
|
||||
|
@ -1468,7 +1468,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
|
|||
* Similar to get_phys_addr, but use the given security space and don't perform
|
||||
* a Granule Protection Check on the resulting address.
|
||||
*/
|
||||
bool get_phys_addr_with_space_nogpc(CPUARMState *env, target_ulong address,
|
||||
bool get_phys_addr_with_space_nogpc(CPUARMState *env, vaddr address,
|
||||
MMUAccessType access_type,
|
||||
ARMMMUIdx mmu_idx, ARMSecuritySpace space,
|
||||
GetPhysAddrResult *result,
|
||||
|
|
|
@ -74,13 +74,13 @@ typedef struct S1Translate {
|
|||
} S1Translate;
|
||||
|
||||
static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw,
|
||||
target_ulong address,
|
||||
vaddr address,
|
||||
MMUAccessType access_type,
|
||||
GetPhysAddrResult *result,
|
||||
ARMMMUFaultInfo *fi);
|
||||
|
||||
static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
|
||||
target_ulong address,
|
||||
vaddr address,
|
||||
MMUAccessType access_type,
|
||||
GetPhysAddrResult *result,
|
||||
ARMMMUFaultInfo *fi);
|
||||
|
@ -3217,7 +3217,7 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
|
|||
*/
|
||||
static bool get_phys_addr_disabled(CPUARMState *env,
|
||||
S1Translate *ptw,
|
||||
target_ulong address,
|
||||
vaddr address,
|
||||
MMUAccessType access_type,
|
||||
GetPhysAddrResult *result,
|
||||
ARMMMUFaultInfo *fi)
|
||||
|
@ -3300,7 +3300,7 @@ static bool get_phys_addr_disabled(CPUARMState *env,
|
|||
}
|
||||
|
||||
static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
|
||||
target_ulong address,
|
||||
vaddr address,
|
||||
MMUAccessType access_type,
|
||||
GetPhysAddrResult *result,
|
||||
ARMMMUFaultInfo *fi)
|
||||
|
@ -3405,7 +3405,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
|
|||
}
|
||||
|
||||
static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw,
|
||||
target_ulong address,
|
||||
vaddr address,
|
||||
MMUAccessType access_type,
|
||||
GetPhysAddrResult *result,
|
||||
ARMMMUFaultInfo *fi)
|
||||
|
@ -3542,7 +3542,7 @@ static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw,
|
|||
}
|
||||
|
||||
static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
|
||||
target_ulong address,
|
||||
vaddr address,
|
||||
MMUAccessType access_type,
|
||||
GetPhysAddrResult *result,
|
||||
ARMMMUFaultInfo *fi)
|
||||
|
@ -3558,7 +3558,7 @@ static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool get_phys_addr_with_space_nogpc(CPUARMState *env, target_ulong address,
|
||||
bool get_phys_addr_with_space_nogpc(CPUARMState *env, vaddr address,
|
||||
MMUAccessType access_type,
|
||||
ARMMMUIdx mmu_idx, ARMSecuritySpace space,
|
||||
GetPhysAddrResult *result,
|
||||
|
@ -3571,7 +3571,7 @@ bool get_phys_addr_with_space_nogpc(CPUARMState *env, target_ulong address,
|
|||
return get_phys_addr_nogpc(env, &ptw, address, access_type, result, fi);
|
||||
}
|
||||
|
||||
bool get_phys_addr(CPUARMState *env, target_ulong address,
|
||||
bool get_phys_addr(CPUARMState *env, vaddr address,
|
||||
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
||||
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
|
||||
{
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
# Functional test that boots a Linux kernel and checks the console
|
||||
#
|
||||
# Copyright (c) 2020 Red Hat, Inc.
|
||||
#
|
||||
# Author:
|
||||
# Thomas Huth <thuth@redhat.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
# later. See the COPYING file in the top-level directory.
|
||||
|
||||
import os
|
||||
|
||||
from avocado import skipUnless
|
||||
from avocado_qemu import QemuSystemTest
|
||||
from avocado_qemu import wait_for_console_pattern
|
||||
|
||||
class N8x0Machine(QemuSystemTest):
|
||||
"""Boots the Linux kernel and checks that the console is operational"""
|
||||
|
||||
timeout = 90
|
||||
|
||||
def __do_test_n8x0(self):
|
||||
kernel_url = ('http://stskeeps.subnetmask.net/meego-n8x0/'
|
||||
'meego-arm-n8x0-1.0.80.20100712.1431-'
|
||||
'vmlinuz-2.6.35~rc4-129.1-n8x0')
|
||||
kernel_hash = 'e9d5ab8d7548923a0061b6fbf601465e479ed269'
|
||||
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
|
||||
|
||||
self.vm.set_console(console_index=1)
|
||||
self.vm.add_args('-kernel', kernel_path,
|
||||
'-append', 'printk.time=0 console=ttyS1')
|
||||
self.vm.launch()
|
||||
wait_for_console_pattern(self, 'TSC2005 driver initializing')
|
||||
|
||||
@skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
|
||||
def test_n800(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:n800
|
||||
"""
|
||||
self.__do_test_n8x0()
|
||||
|
||||
@skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
|
||||
def test_n810(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:n810
|
||||
"""
|
||||
self.__do_test_n8x0()
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* libqos driver framework
|
||||
*
|
||||
* Copyright (c) 2019 Red Hat, Inc.
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "../libqtest.h"
|
||||
#include "libqos-malloc.h"
|
||||
#include "qgraph.h"
|
||||
#include "i2c.h"
|
||||
|
||||
#define ARM_PAGE_SIZE 4096
|
||||
#define N800_RAM_START 0x80000000
|
||||
#define N800_RAM_END 0x88000000
|
||||
|
||||
typedef struct QN800Machine QN800Machine;
|
||||
|
||||
struct QN800Machine {
|
||||
QOSGraphObject obj;
|
||||
QGuestAllocator alloc;
|
||||
OMAPI2C i2c_1;
|
||||
};
|
||||
|
||||
static void *n800_get_driver(void *object, const char *interface)
|
||||
{
|
||||
QN800Machine *machine = object;
|
||||
if (!g_strcmp0(interface, "memory")) {
|
||||
return &machine->alloc;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s not present in arm/n800\n", interface);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static QOSGraphObject *n800_get_device(void *obj, const char *device)
|
||||
{
|
||||
QN800Machine *machine = obj;
|
||||
if (!g_strcmp0(device, "omap_i2c")) {
|
||||
return &machine->i2c_1.obj;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s not present in arm/n800\n", device);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static void n800_destructor(QOSGraphObject *obj)
|
||||
{
|
||||
QN800Machine *machine = (QN800Machine *) obj;
|
||||
alloc_destroy(&machine->alloc);
|
||||
}
|
||||
|
||||
static void *qos_create_machine_arm_n800(QTestState *qts)
|
||||
{
|
||||
QN800Machine *machine = g_new0(QN800Machine, 1);
|
||||
|
||||
alloc_init(&machine->alloc, 0,
|
||||
N800_RAM_START,
|
||||
N800_RAM_END,
|
||||
ARM_PAGE_SIZE);
|
||||
machine->obj.get_device = n800_get_device;
|
||||
machine->obj.get_driver = n800_get_driver;
|
||||
machine->obj.destructor = n800_destructor;
|
||||
|
||||
omap_i2c_init(&machine->i2c_1, qts, 0x48070000);
|
||||
return &machine->obj;
|
||||
}
|
||||
|
||||
static void n800_register_nodes(void)
|
||||
{
|
||||
QOSGraphEdgeOptions edge = {
|
||||
.extra_device_opts = "bus=i2c-bus.0"
|
||||
};
|
||||
qos_node_create_machine("arm/n800", qos_create_machine_arm_n800);
|
||||
qos_node_contains("arm/n800", "omap_i2c", &edge, NULL);
|
||||
}
|
||||
|
||||
libqos_init(n800_register_nodes);
|
|
@ -52,7 +52,6 @@ libqos_srcs = files(
|
|||
# qgraph machines:
|
||||
'aarch64-xlnx-zcu102-machine.c',
|
||||
'arm-imx25-pdk-machine.c',
|
||||
'arm-n800-machine.c',
|
||||
'arm-raspi2-machine.c',
|
||||
'arm-sabrelite-machine.c',
|
||||
'arm-smdkc210-machine.c',
|
||||
|
|
Loading…
Reference in New Issue