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:
Peter Maydell 2024-10-01 17:40:25 +01:00
commit 062cfce8d4
100 changed files with 146 additions and 29043 deletions

View File

@ -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>

View File

@ -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

View File

@ -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)
''''''''''''''''''''''''''''''''''''''''

View File

@ -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
--------------------

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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++) {

View File

@ -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)

View File

@ -25,9 +25,6 @@ config PFLASH_CFI02
config ECC
bool
config ONENAND
bool
config VIRTIO_BLK
bool
default y

View File

@ -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 },

View File

@ -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,

View File

@ -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);

View File

@ -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'))

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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'))

View File

@ -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;

View File

@ -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)

View File

@ -23,3 +23,6 @@ config STM32L4X5_GPIO
config PCF8574
bool
depends on I2C
config ZAURUS_SCOOP
bool

View File

@ -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'))

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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'))

View File

@ -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);
}

View File

@ -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"

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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;
}

View File

@ -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',

View File

@ -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)

View File

@ -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;

View File

@ -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);
}

View File

@ -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 = &regions[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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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'))

View File

@ -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)

View File

@ -14,10 +14,6 @@ config M48T59
config PL031
bool
config TWL92230
bool
depends on I2C
config MC146818RTC
depends on ISA_BUS
bool

View File

@ -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'))

View File

@ -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)

View File

@ -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'))

View File

@ -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);
}

View File

@ -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)

View File

@ -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) {

View File

@ -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"

View File

@ -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'))

View File

@ -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;
}

View File

@ -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) {

View File

@ -21,6 +21,9 @@ config ALLWINNER_A10_PIT
bool
select PTIMER
config PXA2XX_TIMER
bool
config SIFIVE_PWM
bool

View File

@ -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'))

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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'))

View File

@ -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)

View File

@ -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

View File

@ -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 */

View File

@ -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];

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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)
{

View File

@ -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()

View File

@ -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);

View File

@ -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',