qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support
@ 2013-03-15 13:13 Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 01/24] target-arm: add Faraday ARMv5TE processors support Kuo-Jung Su
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Blue Swirl, Paul Brook, Kuo-Jung Su,
	Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A369 SoC platform support.

Here are some public documents for your reference.

http://www.faraday-tech.com/html/documentation/index.html

The partial version of faraday cpu datasheet with only
the CP15 and MPU description are available at my Google Drive:

https://docs.google.com/folder/d/0BwfiewvSmUgAalh5TkxyZWtlWEE/edit?usp=sharing

The pre-built A369 images are also available at my Google Drive:

https://docs.google.com/folder/d/0BwfiewvSmUgAX2pTTmtUMGFCZW8/edit

Here is the image file list:

1. android-4.0.4/zImage: A369 linux-3.0.31
2. android-4.0.4/romfs-4.0.4.tar.bz2: android-4.0.4
3. nand.img.bz2: A369 nand flash image
4. rom.img.bz2: A369 embedded ROM image
5. u-boot: A369 u-boot-2012.10 ELF file
6. zImage: A369 linux-3.4.12 + initramfs
7. README

If you want to re-build the image from scratch, 
try my Faraday Linux BSP/SDK: falinux.

1. Download the falinux

   $ git clone https://github.com/dantesu1218/falinux.git

2. Download all the required software packages:

   $ cd falinux
   $ make setup

3. Launch the menuconfig of falinux, and enable 'QEMU Support'

   $ make menuconfig

4. Re-build the packages

   $ make

5. Laungh the qemu-1.3.0 with the generated falinux images.

   $ make qemu

Changes for v7 -> v8:
    1. [hw/arm/ftintc020.c] (Addressed by Peter)
       'uint32_t mask = BIT(irq % 32);' -> 'uint32_t mask = BIT(irq & 0x1f);'
    2. [hw/arm/*.c] (Addressed by Peter)
       Drop '#include "faraday.h"', and define DPRINTF() at per-file basis
       exit(1) -> abort()
       SysBusDeviceClass::init() -> Device::realize()

Changes for v6 -> v7:

    1. hw/arm/ftwdt010: (Addressed by Paolo)
       Replace 'qemu_system_reset_request()' with 'watchdog_perform_action()'.
    2. hw/arm/ftrtc011: (Addressed by Paolo)
       Replace 'get_clock_realtime()' with 'qemu_get_clock_ns(rtc_clock)'.
       Replace 'qemu_new_timer_ms(rt_clock...)' with 'qemu_new_timer_ms(rtc_clock...)'
       Rename 'ftrtc011_timer_resync' -> 'ftrtc011_timer_rebase'
       Add ftrtc011_timer_resche()
       Add QTest support
    3. hw/arm/faraday_a369_soc: (Addressed by Paolo)
       Remove redundant device reset from a369soc_system_reset(...)
    4. include/qemu/bitops.h: (Addressed by Paolo)
       Update bitrev8() to use a kind of divide and conquer algorithm.
    5. hw/arm/ftahb020,ftddrii030,ftapbbrg020,faraday_a369_soc:
       Drop FARADAY_SOC_GET_CORE(), replaced with device to device QOM link.
    6. hw/wm8731,wm8750,marvell_88w8618_audio,spitz,z2:
       Add AudioCodecClass for wm87xx audio class abstration.
    7. hw/arm/ftnandc021:
       Drop nand_init(), replaced with device to device QOM link.
    8. hw/arm/ftsdc010:
       Bug fixed to write operation: remove sd_data_ready() in write path.
    9. hw/arm/ftgmac100,ftmac110,ftwdt010:
       rt-clock -> vm_clock
   10. hw/nand.c:
       Drop [hw/nand.c: correct the sense of the BUSY/READY], since it's already applied.
       Drop [hw/nand.c: bug fix to erase operation], since Peter has a better solution.

Changes for v5 -> v6:

   1. hw/arm/Makefile.objs: 
       Shift to the next line only after current line length is > 80 characters.
   2. hw/arm/faraday.h:
       Update debug macro format per discussions at the link bellow:
       http://thread.gmane.org/gmane.comp.emulators.qemu/195996/focus=196975
   3. hw/arm/faraday.h:
       TYPE_FARADAY_SOC: 'faraday/soc' -> 'faraday.soc'
   4. hw/arm/*.c:
       Replace '%llx' with '%HWADDR_PRIx'
   5. hw/arm/*.h:
       Add '#include "qemu/bitops.h"'
   6. hw/arm/faraday_a369_soc.c:
       Typo fix: salve4 -> slave4, salve6 -> slave6
   7. hw/arm/*.c:
       Drop FROM_SYSBUS().
   8. hw/arm/ftintc020.c:
       Re-write the source file with pl190.c as template.
   9. hw/arm/ftintc020.h:
       Rename the registers to improve readibility.
   10. hw/arm/faraday.h:
       Add dedicated spi flash pointer array (DeviceState *spi_fl[2]).
   11. hw/arm/faraday.h:
       Add 'qemu_irq pic[64]'.
   12. hw/arm/*c:
       Replace the complex conversion in XXX_REG32() with directly array indexing.
   13. hw/arm/*c:
       Update the error message output from 'hw_error(...)' into 'fprintf(stderr, ...)'
   14. hw/arm/faraday_a369.c, hw/arm/faraday_a369_soc.c:
       Move the external AHB device init from faraday_a369_soc.c to faraday_a369.c
   15. include/qemu/bitops.h:
       Move bitrev() from bitrev.[ch] into bitops.h
   16. hw/nand.c:
       Remove the clear/set SR[6] code in read/erase/write, because
       it's not possible to be observed by a guest.
   17. hw/arm/faraday_a369_kpd.c:
       Function prefix: 'ftkbc010' -> 'a369kpd' 
       Name of struct:  'FTKBC010State' -> 'A369KPDState'.
       QOM: 'FTKBC010' -> 'A369KPD'
   18. hw/arm/ftddrii030.c:
       'case REG_MCR ... 0x4c' -> 'case REG_MCR ... (CFG_REGSIZE - 1) * 4'
   19. hw/arm/ftahbc020.c:
       Add comments to fall-through path. (i.e. /* fall-through - skip slave6 */)
   20. hw/arm/faraday_a369.c:
       Update spi flash init code to use the new QOM classes of m25p80.

Changes for v3 -> v5:

   1. [cpu] Add the unapplied patches for faraday ARMv5TE cores.
   2. [nand] Add the unapplied patches for hw/nand.c.
   3. [audio] Add the unapplied patches for wm8731.
   4. [Global] Replace redundant statement in xxx_update_irq() with
            qemu_set_irq(s->irq, !!(xxxx));
   5. [Global] Introduce 'case xxx ... xxx' statement in switch { }
            to replace the 'if {} else {}' statement.
   6. [Global] Replace complex bitwise operation with functions defined in bitops.h
   7. [Global] Introduce array register caches (i.e. s->regs[]) implementation
            to fttsc010, ftrtc011, ftmac110, ftgmac100, ftddrii030
            faraday_a369_kpd and faraday_a369_soc.
   8. [Global] Add qemu_log_mask(LOG_GUEST_ERROR...) on undefined memory accesses.
   9. [Global] Add missing register access size constraint to
            faraday_a369_kpd, faraday_a369_soc, ftahbc020.c, ftddrii030.c,
            ftintc020.c, ftlcdc200.c, ftpwmtmr010.c, ftspi020.c, fttmr010.c
            and fttsc010.c.
  10. [Global] Add more register and bitmask descriptions to all the chips.
  11. [Global] Rename all the MemoryRegionOps variables to 'mmio_ops'
  12. [Global] Update all non-system header includes from '<>' into '""'
  13. [bitrev] Port bitrev.[ch] from linux kernel into QEMU.
  14. [ftapbbrg020] Replace cpu_physical_memory_read()/cpu_physical_memory_write()
            with dma_memory_read()/dma_memory_write()
  15. [ftdmac020] Replace cpu_physical_memory_read()/cpu_physical_memory_write()
            with dma_memory_read()/dma_memory_write()
  16. [ftgmac100/ftmac110] Replace cpu_physical_memory_read()/cpu_physical_memory_write()
            with dma_memory_read()/dma_memory_write()
  17. [ftgmac100/ftmac110] Add a 10ms timer for polling the owner bit of descriptors
              to call qemu_flush_queued_packets() when it's necessary.
  18. [ftgmac100/ftmac110] Replace hw_error() with qemu_log_mask(LOG_GUEST_ERROR, ) 
              for programmer errors.
  19. [ftgmac100/ftmac110] Update descriptor struct for big endian QEMU host support.
  20. [ftgmac100/ftmac110] Typo fix ('FTMAC_H' --> 'HW_ARM_FTMAC110_H') to the header files.
  21. [ftmac110] Update mdio phy response emulation from Marvell into Davicom PHY.
  22. [ftwdt010/fttsc010] Switch to a slower timer. (i.e. rt_clock)

  23. [faraday_a360] Removed. The ftmac110 and fttmr010 has been moved to 
              A369 as external AHB devices.  
  24. [faraday_a369] Add register caches for AHB/APB slave devices.
  25. [faraday_a369] Remember (arm_boot_info *) when launching in direct boot mode.
  26. [faraday_a369] Replace pointer to (mach *) with QOM APIs. (i.e. no more DEFINE_PROP_PTR())
  27. [faraday_a369] Add a error message for ROM mode when it failed to load image.
  28. [faraday_a369] Add the missing AHB remap process into direct boot mode.
  29. [faraday_a369] Bug fix to ROM and RAM memory overlap issue.
  30. [faraday_a369] Remove system reset order dependency from ftddrii030 and ftahbc020
  31. [faraday_a369] Separate the a369 platform implementation into 2 different parts:
              board=faraday_a369.c, and soc=faraday_a369_soc.c
  32. [faraday_a369] Copy all the un-used register values from read hardware into QEMU model.
  33. [ftssp010] Add address alignment checker.
  34. [ftssp010] Move the audio codec initialization code to faraday_a369.c.
  35. [ftspi020] Use a constant (CFG_NR_CSLINES) for the number of cs lines.
  36. [ftspi020] Replace 's->datacnt <= 0' with '!s->datacnt', because s->datacnt is unsigned.
  37. [ftspi020] Replace 's->datacnt' with 's->cmd[2]'
  38. [ftspi020] Remove redundant M25P80s command opcodes from the header file.
  39. [ftspi020] Replace 'g_new' with 'g_new0' for cs_lines allocation.
              This fix the bug which crash the QEMU when de-activating an unattached
              spi flash chip select. Thanks to Peter.

Changes for v3:
   
   1. [global] review all commit log make sure it correctly
               describe the QEMU model.
   2. [global] reformat the entire patch series to be compilable 
               on its own. Thanks to Andreas and Igor.
   3. [global] move all files from 'hw' into 'hw/arm', and 
               rename a36x.c to faraday_a36x.c
   4. [global] update lisence to GPLv2+
   5. [global] rename both struct and typedef names to CamelCase.
   6. [global] turn printfs into DPRINTF() which is controlled 
               by 'DEBUG_FARADAY'
   7. [global] remove disabled code.
   8. [global] add header files with descriptive defines to 
               ftintc020, ftrtc011, fttmr010 ... etc.
   9. [global] update all header file to have a 'HW_ARM_' prefix 
               to header guards.
  10. [faraday.h] add parameter names to ftmac110_init() and
                  ftgmac100_init()
  11. [a360/a369] remove printf("xxx %dMB ram.\n"...);
  12. [a360/a369] add 'arm926' as a fail-safe cpu model.
  13. [a360/a369] add DEFAULT_MACHINE_OPTIONS.
  14. [a360/a369] remove USB-EHCI support, it's now a standalone patch.
  15. [a360] replace ftlcdc200 init from sysbus_create_varargs() to
             sysbus_create_simple().
  16. [a360] make PMU a standalone file. (faraday_a360_pmu.c)
  17. [a369] make SCU a standalone file. (faraday_a369_pcu.c)
  18. [a369] make AHBC a standalone file. (ftahbc020.c)
  19. [a369] make DDRC a standalone file. (ftddrii030.c)
  20. [a369] rename ftkbc010 to faraday_a369_keypad.c
  21. [a369] replace ROM emulation with PFLASH.(rom.c is deleted)
  22. [ftsdc010] add sd_data_ready() to data R/W.
  23. [ftsdc010] check 'datacnt' at each read/write to make sure
             buffer would not overflow/underflow and also prevent
             'datacnt' from underflow by subtracted by a 4.
  24. [ftgmac100] add 802.1Q VLAN tag insertion/removal support.
  25. [ftgmac100] replace the dumb timer code with bottom half.
  26. [ftgmac100] rename the struct name of descriptors to CamelCase.
  27. [ftgmac100] replace 'void *' with 'Ftgmac100RXD *' and 
                  'Ftgmac100TXD *' for descriptor read/write.
  28. [ftgmac100] add buffer overflow check in ftgmac100_transmit()
  29. [ftgmac100] add buffer alignment check
  30. [ftmac110] replace the dumb timer code with bottom half.
  31. [ftmac110] rename the struct name of descriptors to CamelCase.
  32. [ftmac110] replace 'void *' with 'Ftmac110RXD *' and
                 'Ftmac110TXD *' for descriptor read/write.
  33. [ftmac110] add buffer overflow check in ftmac110_transmit()
  34. [ftmac110] add buffer alignment check
  35. [ftdmac020] replace the dumb timer code with bottom half.
  36. [ftdmac020] replace cpu_physical_memory_map() with 
                  cpu_physical_memory_read/write() for both simplicity
                  and security enhancement which caused by the un-checked
                  return mapped length from cpu_physical_memory_map().
  37. [ftapbbrg020] replace the dumb timer code with bottom half.
  38. [ftapbbrg020] replace cpu_physical_memory_map() with 
                  cpu_physical_memory_read/write() for both simplicity
                  and security enhancement which caused by the un-checked
                  return mapped length from cpu_physical_memory_map().
  39. [ftrtc011] switch to a slower timer with msec resolution. (i.e. rt_clock)
  40. [ftrtc011] re-calculate RTC counters from host timestamp upon register 
                 read/write and also vm save/restore.

Changes for v2:

   1. coding style fixes (verified with checkpatch.pl)
   2. add Faraday A360 support
   3. add Faraday USB 2.0 EHCI support
   4. merge a369_scu.c into a369.c
   5. introduce QOM coding style
   6. remove lowercase Macros: min(), max()
   7. name all struct as CamelCase style
   8. move function prototypes from .c to faraday.h
   9. use switch instead of if statement in a369_ahbc_write
  10. remove debug prints
  11. update all uarts in A36x to DEVICE_LITTLE_ENDIAN.
  12. move the variable definitions to the start of the function,
      instead of inside a do { } while(0)
  13. remove disabled and commented out code.
  14. use hw_error() and exit() upon pflash register failed.
  15. add const prior to TypeInfo (i.e. static *const*
      TypeInfo ftrtc011_info)
  16. add le32_to_cpu/cpu_to_le32 to the descriptor processing in
      FTGMAC100/FTMAC110.
  17. update the GPL license to GPL v2 (except for FTLCDC200,
      it's based on pl110.c which is LGPL.)
  18. add const to src_* in the DMA controllers (FTAPBBRG020/FTDMAC020)


Kuo-Jung Su (24):
  target-arm: add Faraday ARMv5TE processors support
  hw/arm: add Faraday a369 SoC platform support
  hw/arm: add FTINTC020 interrupt controller support
  hw/arm: add FTAHBC020 AHB controller support
  hw/arm: add FTDDRII030 DDRII controller support
  hw/arm: add FTPWMTMR010 timer support
  hw/arm: add FTWDT010 watchdog timer support
  hw/arm: add FTRTC011 RTC timer support
  tests: add QTest for FTRTC011
  hw/arm: add FTDMAC020 AHB DMA support
  hw/arm: add FTAPBBRG020 APB DMA support
  hw/arm: add FTNANDC021 nand flash controller support
  hw/arm: add FTI2C010 I2C controller support
  hw: Add AudioCodecClass for wm87xx audio class abstration.
  hw: add WM8731 audio codec support
  hw/arm: add FTSSP010 multi-function controller support
  qemu/bitops.h: add the bit ordering reversal functions
  hw/arm: add FTGMAC100 1Gbps ethernet support
  hw/arm: add FTLCDC200 LCD controller support
  hw/arm: add FTTSC010 touchscreen controller support
  hw/arm: add FTSDC010 MMC/SD controller support
  hw/arm: add FTMAC110 10/100Mbps ethernet support
  hw/arm: add FTTMR010 timer support
  hw/arm: add FTSPI020 SPI flash controller support

 default-configs/arm-softmmu.mak |    1 +
 hw/Makefile.objs                |    2 +
 hw/arm/Makefile.objs            |   21 ++
 hw/arm/faraday.h                |   61 ++++
 hw/arm/faraday_a369.c           |  174 ++++++++++
 hw/arm/faraday_a369_kpd.c       |  231 +++++++++++++
 hw/arm/faraday_a369_scu.c       |  182 ++++++++++
 hw/arm/faraday_a369_soc.c       |  342 +++++++++++++++++++
 hw/arm/ftahbc020.c              |  202 +++++++++++
 hw/arm/ftapbbrg020.c            |  468 ++++++++++++++++++++++++++
 hw/arm/ftapbbrg020.h            |   44 +++
 hw/arm/ftddrii030.c             |  183 ++++++++++
 hw/arm/ftdmac020.c              |  595 ++++++++++++++++++++++++++++++++
 hw/arm/ftdmac020.h              |  107 ++++++
 hw/arm/ftgmac100.c              |  708 +++++++++++++++++++++++++++++++++++++++
 hw/arm/ftgmac100.h              |  239 +++++++++++++
 hw/arm/fti2c010.c               |  212 ++++++++++++
 hw/arm/fti2c010.h               |   71 ++++
 hw/arm/ftintc020.c              |  302 +++++++++++++++++
 hw/arm/ftintc020.h              |   57 ++++
 hw/arm/ftkbc010.h               |   44 +++
 hw/arm/ftlcdc200.c              |  510 ++++++++++++++++++++++++++++
 hw/arm/ftlcdc200.h              |  112 +++++++
 hw/arm/ftlcdc200_template.h     |  439 ++++++++++++++++++++++++
 hw/arm/ftmac110.c               |  661 ++++++++++++++++++++++++++++++++++++
 hw/arm/ftmac110.h               |  168 ++++++++++
 hw/arm/ftnandc021.c             |  516 ++++++++++++++++++++++++++++
 hw/arm/ftnandc021.h             |   84 +++++
 hw/arm/ftpwmtmr010.c            |  258 ++++++++++++++
 hw/arm/ftpwmtmr010.h            |   31 ++
 hw/arm/ftrtc011.c               |  383 +++++++++++++++++++++
 hw/arm/ftrtc011.h               |   53 +++
 hw/arm/ftsdc010.c               |  354 ++++++++++++++++++++
 hw/arm/ftsdc010.h               |   90 +++++
 hw/arm/ftspi020.c               |  337 +++++++++++++++++++
 hw/arm/ftspi020.h               |   81 +++++
 hw/arm/ftssp010.c               |  494 +++++++++++++++++++++++++++
 hw/arm/ftssp010.h               |   98 ++++++
 hw/arm/fttmr010.c               |  445 ++++++++++++++++++++++++
 hw/arm/fttmr010.h               |   41 +++
 hw/arm/fttsc010.c               |  260 ++++++++++++++
 hw/arm/fttsc010.h               |   39 +++
 hw/arm/ftwdt010.c               |  209 ++++++++++++
 hw/arm/ftwdt010.h               |   35 ++
 hw/arm/spitz.c                  |    9 +-
 hw/arm/z2.c                     |    9 +-
 hw/audio_codec.c                |   81 +++++
 hw/audio_codec.h                |   56 ++++
 hw/i2c.h                        |    9 -
 hw/marvell_88w8618_audio.c      |   23 +-
 hw/wm8731.c                     |  505 ++++++++++++++++++++++++++++
 hw/wm8750.c                     |   91 ++---
 include/qemu/bitops.h           |   59 +++-
 target-arm/cpu.c                |   52 +++
 target-arm/cpu.h                |    6 +-
 target-arm/helper.c             |   84 +++++
 target-arm/machine.c            |    4 +
 tests/Makefile                  |    3 +
 tests/ftrtc011-test.c           |  410 +++++++++++++++++++++++
 59 files changed, 11275 insertions(+), 70 deletions(-)
 create mode 100644 hw/arm/faraday.h
 create mode 100644 hw/arm/faraday_a369.c
 create mode 100644 hw/arm/faraday_a369_kpd.c
 create mode 100644 hw/arm/faraday_a369_scu.c
 create mode 100644 hw/arm/faraday_a369_soc.c
 create mode 100644 hw/arm/ftahbc020.c
 create mode 100644 hw/arm/ftapbbrg020.c
 create mode 100644 hw/arm/ftapbbrg020.h
 create mode 100644 hw/arm/ftddrii030.c
 create mode 100644 hw/arm/ftdmac020.c
 create mode 100644 hw/arm/ftdmac020.h
 create mode 100644 hw/arm/ftgmac100.c
 create mode 100644 hw/arm/ftgmac100.h
 create mode 100644 hw/arm/fti2c010.c
 create mode 100644 hw/arm/fti2c010.h
 create mode 100644 hw/arm/ftintc020.c
 create mode 100644 hw/arm/ftintc020.h
 create mode 100644 hw/arm/ftkbc010.h
 create mode 100644 hw/arm/ftlcdc200.c
 create mode 100644 hw/arm/ftlcdc200.h
 create mode 100644 hw/arm/ftlcdc200_template.h
 create mode 100644 hw/arm/ftmac110.c
 create mode 100644 hw/arm/ftmac110.h
 create mode 100644 hw/arm/ftnandc021.c
 create mode 100644 hw/arm/ftnandc021.h
 create mode 100644 hw/arm/ftpwmtmr010.c
 create mode 100644 hw/arm/ftpwmtmr010.h
 create mode 100644 hw/arm/ftrtc011.c
 create mode 100644 hw/arm/ftrtc011.h
 create mode 100644 hw/arm/ftsdc010.c
 create mode 100644 hw/arm/ftsdc010.h
 create mode 100644 hw/arm/ftspi020.c
 create mode 100644 hw/arm/ftspi020.h
 create mode 100644 hw/arm/ftssp010.c
 create mode 100644 hw/arm/ftssp010.h
 create mode 100644 hw/arm/fttmr010.c
 create mode 100644 hw/arm/fttmr010.h
 create mode 100644 hw/arm/fttsc010.c
 create mode 100644 hw/arm/fttsc010.h
 create mode 100644 hw/arm/ftwdt010.c
 create mode 100644 hw/arm/ftwdt010.h
 create mode 100644 hw/audio_codec.c
 create mode 100644 hw/audio_codec.h
 create mode 100644 hw/wm8731.c
 create mode 100644 tests/ftrtc011-test.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 01/24] target-arm: add Faraday ARMv5TE processors support
  2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
@ 2013-03-15 13:13 ` Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 02/24] hw/arm: add Faraday a369 SoC platform support Kuo-Jung Su
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Blue Swirl, Paul Brook, Kuo-Jung Su,
	Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch includes the single core support to FA606TE, FA626TE,
FA616TE and FA726TE with CP15 Faraday extensions (AUX and I/D-Scratchpad).

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 target-arm/cpu.c     |   52 +++++++++++++++++++++++++++++++
 target-arm/cpu.h     |    6 +++-
 target-arm/helper.c  |   84 ++++++++++++++++++++++++++++++++++++++++++++++++++
 target-arm/machine.c |    4 +++
 4 files changed, 145 insertions(+), 1 deletion(-)

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index a1e9093..aed97b0 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -244,6 +244,54 @@ static void arm926_initfn(Object *obj)
     cpu->reset_sctlr = 0x00090078;
 }
 
+static void fa606te_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_feature(&cpu->env, ARM_FEATURE_MPU_FARADAY);
+    cpu->midr = 0x66056061; /* CR0-0 Identification Code Register (ID) */
+    cpu->ctr = 0x00000000;  /* CR0-1 Cache Type Register (CTR) */
+    cpu->reset_sctlr = 0x00000078;  /* CR1-0 Configuration Register (CFG) */
+}
+
+static void fa616te_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
+    set_feature(&cpu->env, ARM_FEATURE_TCM_FARADAY);
+    cpu->midr = 0x66056161; /* CR0-0 Identification Code Register (ID) */
+    cpu->ctr = 0x1d152152;  /* CR0-1 Cache Type Register (CTR) */
+    cpu->reset_sctlr = 0x00050078;  /* CR1-0 Configuration Register (CFG) */
+}
+
+static void fa626te_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
+    set_feature(&cpu->env, ARM_FEATURE_TCM_FARADAY);
+    set_feature(&cpu->env, ARM_FEATURE_AUXCR);
+    cpu->midr = 0x66056261; /* CR0-0 Identification Code Register (ID) */
+    cpu->ctr = 0x0f192192;  /* CR0-1 Cache Type Register (CTR) */
+    cpu->reset_sctlr = 0x00000078;  /* CR1-0 Configuration Register (CFG) */
+}
+
+static void fa726te_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
+    set_feature(&cpu->env, ARM_FEATURE_TCM_FARADAY);
+    cpu->midr = 0x66057261; /* CR0-0 Identification Code Register (ID) */
+    cpu->ctr = 0x1d192192;  /* CR0-1 Cache Type Register (CTR) */
+    cpu->reset_sctlr = 0x00050078;  /* CR1-0 Configuration Register (CFG) */
+}
+
 static void arm946_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
@@ -766,6 +814,10 @@ typedef struct ARMCPUInfo {
 
 static const ARMCPUInfo arm_cpus[] = {
     { .name = "arm926",      .initfn = arm926_initfn },
+    { .name = "fa606te",     .initfn = fa606te_initfn },
+    { .name = "fa616te",     .initfn = fa616te_initfn },
+    { .name = "fa626te",     .initfn = fa626te_initfn },
+    { .name = "fa726te",     .initfn = fa726te_initfn },
     { .name = "arm946",      .initfn = arm946_initfn },
     { .name = "arm1026",     .initfn = arm1026_initfn },
     /* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 2b97221..dd27e80 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -152,6 +152,8 @@ typedef struct CPUARMState {
         uint32_t c15_diagnostic; /* diagnostic register */
         uint32_t c15_power_diagnostic;
         uint32_t c15_power_control; /* power control */
+        uint32_t c15_tcm_data;      /* Data TCM region register */
+        uint32_t c15_tcm_inst;      /* Instruction TCM region register */
     } cp15;
 
     struct {
@@ -392,6 +394,8 @@ enum arm_features {
     ARM_FEATURE_MPIDR, /* has cp15 MPIDR */
     ARM_FEATURE_PXN, /* has Privileged Execute Never bit */
     ARM_FEATURE_LPAE, /* has Large Physical Address Extension */
+    ARM_FEATURE_TCM_FARADAY, /* Faraday Scratchpad(TCM) */
+    ARM_FEATURE_MPU_FARADAY, /* Faraday MPU */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -640,7 +644,7 @@ static inline CPUARMState *cpu_init(const char *cpu_model)
 #define cpu_signal_handler cpu_arm_signal_handler
 #define cpu_list arm_cpu_list
 
-#define CPU_SAVE_VERSION 9
+#define CPU_SAVE_VERSION 10
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
diff --git a/target-arm/helper.c b/target-arm/helper.c
index fd055e8..337d8b8 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1015,6 +1015,84 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
     REGINFO_SENTINEL
 };
 
+static int faraday_pmsav5_ircfg_read(CPUARMState *env,
+                                     const ARMCPRegInfo *ri,
+                                     uint64_t *value)
+{
+    if (ri->crm >= 4) {
+        return EXCP_UDEF;
+    }
+    *value = env->cp15.c6_region[ri->crm];
+    return 0;
+}
+
+static int faraday_pmsav5_ircfg_write(CPUARMState *env,
+                                      const ARMCPRegInfo *ri,
+                                      uint64_t value)
+{
+    if (ri->crm >= 4) {
+        return EXCP_UDEF;
+    }
+    env->cp15.c6_region[ri->crm] = value;
+    return 0;
+}
+
+static int faraday_pmsav5_drcfg_read(CPUARMState *env,
+                                     const ARMCPRegInfo *ri,
+                                     uint64_t *value)
+{
+    if (ri->crm >= 4) {
+        return EXCP_UDEF;
+    }
+    *value = env->cp15.c6_region[ri->crm + 4];
+    return 0;
+}
+
+static int faraday_pmsav5_drcfg_write(CPUARMState *env,
+                                      const ARMCPRegInfo *ri,
+                                      uint64_t value)
+{
+    if (ri->crm >= 4) {
+        return EXCP_UDEF;
+    }
+    env->cp15.c6_region[ri->crm + 4] = value;
+    return 0;
+}
+
+static const ARMCPRegInfo faraday_pmsav5_cp_reginfo[] = {
+    /* Data region access permission */
+    { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW,
+      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0,
+      .readfn = pmsav5_data_ap_read, .writefn = pmsav5_data_ap_write, },
+    /* Instruction region access permission */
+    { .name = "INSN_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
+      .access = PL1_RW,
+      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0,
+      .readfn = pmsav5_insn_ap_read, .writefn = pmsav5_insn_ap_write, },
+    /* Data region base and size registers */
+    { .name = "DR_CFG", .cp = 15, .crn = 6, .crm = CP_ANY,
+      .opc1 = 0, .opc2 = 0, .access = PL1_RW,
+      .readfn = faraday_pmsav5_drcfg_read,
+      .writefn = faraday_pmsav5_drcfg_write, },
+    /* Instruction region base and size registers */
+    { .name = "IR_CFG", .cp = 15, .crn = 6, .crm = CP_ANY,
+      .opc1 = 0, .opc2 = 1, .access = PL1_RW,
+      .readfn = faraday_pmsav5_ircfg_read,
+      .writefn = faraday_pmsav5_ircfg_write, },
+    REGINFO_SENTINEL
+};
+
+static const ARMCPRegInfo faraday_tcm_cp_reginfo[] = {
+    { .name = "DTCMRR", .cp = 15, .crn = 9, .crm = 1,
+      .opc1 = 0, .opc2 = 0, .access = PL1_RW, .resetvalue = 0x0,
+      .fieldoffset = offsetof(CPUARMState, cp15.c15_tcm_data) },
+    { .name = "ITCMRR", .cp = 15, .crn = 9, .crm = 1,
+      .opc1 = 0, .opc2 = 1, .access = PL1_RW, .resetvalue = 0x0,
+      .fieldoffset = offsetof(CPUARMState, cp15.c15_tcm_inst) },
+    REGINFO_SENTINEL
+};
+
 static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     env->cp15.c1_sys = value;
@@ -1163,6 +1241,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     if (arm_feature(env, ARM_FEATURE_LPAE)) {
         define_arm_cp_regs(cpu, lpae_cp_reginfo);
     }
+    if (arm_feature(env, ARM_FEATURE_TCM_FARADAY)) {
+        define_arm_cp_regs(cpu, faraday_tcm_cp_reginfo);
+    }
+    if (arm_feature(env, ARM_FEATURE_MPU_FARADAY)) {
+        define_arm_cp_regs(cpu, faraday_pmsav5_cp_reginfo);
+    }
     /* Slightly awkwardly, the OMAP and StrongARM cores need all of
      * cp15 crn=0 to be writes-ignored, whereas for other cores they should
      * be read-only (ie write causes UNDEF exception).
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 68dca7f..ed63614 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -62,6 +62,8 @@ void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, env->cp15.c15_power_control);
     qemu_put_be32(f, env->cp15.c15_diagnostic);
     qemu_put_be32(f, env->cp15.c15_power_diagnostic);
+    qemu_put_be32(f, env->cp15.c15_tcm_data);
+    qemu_put_be32(f, env->cp15.c15_tcm_inst);
 
     qemu_put_be64(f, env->features);
 
@@ -182,6 +184,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     env->cp15.c15_power_control = qemu_get_be32(f);
     env->cp15.c15_diagnostic = qemu_get_be32(f);
     env->cp15.c15_power_diagnostic = qemu_get_be32(f);
+    env->cp15.c15_tcm_data = qemu_get_be32(f);
+    env->cp15.c15_tcm_inst = qemu_get_be32(f);
 
     env->features = qemu_get_be64(f);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 02/24] hw/arm: add Faraday a369 SoC platform support
  2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 01/24] target-arm: add Faraday ARMv5TE processors support Kuo-Jung Su
@ 2013-03-15 13:13 ` Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 03/24] hw/arm: add FTINTC020 interrupt controller support Kuo-Jung Su
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Blue Swirl, Paul Brook, Kuo-Jung Su,
	Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday A369 EVB is a Faraday SoC platform evalution board used for
Faraday IP functional verification based on the well-known ARM AMBA 2.0
architecture.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs      |    3 +
 hw/arm/faraday.h          |   52 ++++++++++
 hw/arm/faraday_a369.c     |   98 +++++++++++++++++++
 hw/arm/faraday_a369_kpd.c |  231 +++++++++++++++++++++++++++++++++++++++++++++
 hw/arm/faraday_a369_scu.c |  182 +++++++++++++++++++++++++++++++++++
 hw/arm/faraday_a369_soc.c |  190 +++++++++++++++++++++++++++++++++++++
 hw/arm/ftkbc010.h         |   44 +++++++++
 7 files changed, 800 insertions(+)
 create mode 100644 hw/arm/faraday.h
 create mode 100644 hw/arm/faraday_a369.c
 create mode 100644 hw/arm/faraday_a369_kpd.c
 create mode 100644 hw/arm/faraday_a369_scu.c
 create mode 100644 hw/arm/faraday_a369_soc.c
 create mode 100644 hw/arm/ftkbc010.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index f5f7d0e..104e0e7 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -34,3 +34,6 @@ obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
 
 obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-y += omap1.o omap2.o
+
+obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
+            faraday_a369_kpd.o
diff --git a/hw/arm/faraday.h b/hw/arm/faraday.h
new file mode 100644
index 0000000..4a9c2ae
--- /dev/null
+++ b/hw/arm/faraday.h
@@ -0,0 +1,52 @@
+/*
+ * Faraday SoC platform support.
+ *
+ * Copyright (c) 2013 Faraday Technology
+ * Written by Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#ifndef HW_ARM_FARADAY_H
+#define HW_ARM_FARADAY_H
+
+#include "hw/flash.h"
+#include "qemu/bitops.h"
+
+typedef struct FaradaySoCState {
+    SysBusDevice busdev;
+    hwaddr       rom_base;
+    uint64_t     rom_size;
+    hwaddr       ram_base;
+    uint64_t     ram_size;
+    char         *cpu_model;
+    ARMCPU       *cpu;
+    qemu_irq     pic[64];
+    DeviceState  *scu;      /* System Control Unit */
+    DeviceState  *ahbc;     /* AHB controller */
+    DeviceState  *ddrc;     /* DDR controller */
+    DeviceState  *hdma[2];  /* AHB DMA */
+    DeviceState  *pdma[1];  /* APB DMA */
+    DeviceState  *spi[2];   /* Generic SPI bus */
+    DeviceState  *spi_fl[2];/* Dedicated SPI bus for flash memory */
+    DeviceState  *i2c[2];   /* Generic I2C bus */
+    DeviceState  *i2s[2];   /* Generic I2S bus */
+    DeviceState  *nandc[2]; /* NAND flash controller */
+
+    MemoryRegion *as;       /* address space */
+    MemoryRegion *ram;      /* external sdram */
+    pflash_t     *rom;      /* on-chip rom */
+    MemoryRegion *sram;     /* on-chip static ram */
+
+    uint32_t ahb_slave[32];
+    uint32_t apb_slave[32];
+    bool     ahb_remapped;
+    bool     ddr_inited;
+    struct arm_boot_info *bi;
+} FaradaySoCState;
+
+/* SoC common APIs */
+#define TYPE_FARADAY_SOC    "faraday.soc"
+#define FARADAY_SOC(obj) \
+    OBJECT_CHECK(FaradaySoCState, obj, TYPE_FARADAY_SOC)
+
+#endif
diff --git a/hw/arm/faraday_a369.c b/hw/arm/faraday_a369.c
new file mode 100644
index 0000000..3a89a04
--- /dev/null
+++ b/hw/arm/faraday_a369.c
@@ -0,0 +1,98 @@
+/*
+ * Faraday A369 Evalution Board
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/i2c.h"
+#include "hw/boards.h"
+#include "hw/ssi.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+
+#include "faraday.h"
+
+/* Board init.  */
+
+static void
+a369_board_init(QEMUMachineInitArgs *args)
+{
+    DeviceState *ds;
+    FaradaySoCState *s;
+
+    if (!args->cpu_model) {
+        args->cpu_model = "fa626te";
+    }
+
+    if (!args->ram_size) {
+        args->ram_size = 512 << 20;
+    }
+
+    ds = qdev_create(NULL, TYPE_FARADAY_SOC);
+    qdev_prop_set_string(ds, "cpu_model", args->cpu_model);
+    qdev_prop_set_uint64(ds, "ram_size", args->ram_size);
+    /* Setup QOM path for the SoC object (i.e. /machine/faraday.soc) */
+    object_property_add_child(qdev_get_machine(),
+                              TYPE_FARADAY_SOC,
+                              OBJECT(ds),
+                              NULL);
+    qdev_init_nofail(ds);
+
+    s = FARADAY_SOC(ds);
+
+    /* System start-up */
+
+    if (args->kernel_filename) {
+        s->bi = g_new0(struct arm_boot_info, 1);
+
+        s->ddr_inited = true;
+        s->ahb_remapped = true;
+
+        /* Remap AHB slave 4 (ROM) & slave 6 (RAM) */
+        /* 1. Remap RAM to base of ROM */
+        s->ram_base = s->ahb_slave[4] & 0xfff00000;
+        s->ahb_slave[6] = s->ram_base | (s->ahb_slave[6] & 0x000f0000);
+        /* 2. Remap ROM to base of ROM + size of RAM */
+        s->rom_base = s->ram_base
+                    + ((1 << extract32(s->ahb_slave[6], 16, 4)) << 20);
+        s->ahb_slave[4] = s->rom_base | (s->ahb_slave[4] & 0x000f0000);
+
+        /* 3. Update ROM Address */
+        sysbus_mmio_map(SYS_BUS_DEVICE(s->rom), 0, s->rom_base);
+
+        /* 4. RAM Address Binding */
+        memory_region_add_subregion(s->as, s->ram_base, s->ram);
+
+        /* 5. Boot Info */
+        s->bi->ram_size = s->ram_size;
+        s->bi->kernel_filename = args->kernel_filename;
+        s->bi->kernel_cmdline = args->kernel_cmdline;
+        s->bi->initrd_filename = args->initrd_filename;
+        s->bi->board_id = 0x3369;
+        arm_load_kernel(s->cpu, s->bi);
+    } else if (!drive_get(IF_PFLASH, 0, 0)) {
+        fprintf(stderr, "a369: Unable to load ROM image!\n");
+        abort();
+    }
+}
+
+static QEMUMachine a369_machine = {
+    .name = "a369",
+    .desc = "Faraday A369 (fa626te)",
+    .init = a369_board_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void
+a369_machine_init(void)
+{
+    qemu_register_machine(&a369_machine);
+}
+
+machine_init(a369_machine_init);
diff --git a/hw/arm/faraday_a369_kpd.c b/hw/arm/faraday_a369_kpd.c
new file mode 100644
index 0000000..7b27725
--- /dev/null
+++ b/hw/arm/faraday_a369_kpd.c
@@ -0,0 +1,231 @@
+/*
+ * Faraday FTKBC010 emulator for A369.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * In A369 EVB, the FTKBC010 is configured as a keypad controller.
+ * It acts like a group of hard wired buttons on the board, each of them
+ * is monitored by the FTKBC010, and coordinated as (x, y).
+ * However there is a pinmux issue in A369 EVB, the Y-axis usually
+ * malfunctioned, so there are only 3 button emulated here.
+ *
+ * This code is licensed under GNU GPL v2+
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "ui/console.h"
+#include "sysemu/sysemu.h"
+
+#include "ftkbc010.h"
+
+#define CFG_REGSIZE     (0x3c / 4)
+
+/* Key codes */
+#define KEYCODE_ESC             1
+#define KEYCODE_BACKSPACE       14
+#define KEYCODE_ENTER           28
+#define KEYCODE_SPACE           57
+#define KEYCODE_MENU            139    /* Menu (show menu) */
+
+#define TYPE_A369KPD            "a369.kpd"
+
+typedef struct A369KPDState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    /* HW registers */
+    uint32_t regs[CFG_REGSIZE];
+} A369KPDState;
+
+#define A369KPD(obj) \
+    OBJECT_CHECK(A369KPDState, obj, TYPE_A369KPD)
+
+#define KBC_REG32(s, off) \
+    ((s)->regs[(off) / 4])
+
+static void a369kpd_update_irq(A369KPDState *s)
+{
+    uint32_t ier = 0;
+
+    /* keypad interrupt */
+    ier |= (KBC_REG32(s, REG_CR) & CR_KPDEN) ? ISR_KPDI : 0;
+    /* tx interrupt */
+    ier |= (KBC_REG32(s, REG_CR) & CR_TXIEN) ? ISR_TXI : 0;
+    /* rx interrupt */
+    ier |= (KBC_REG32(s, REG_CR) & CR_RXIEN) ? ISR_RXI : 0;
+
+    qemu_set_irq(s->irq, (ier & KBC_REG32(s, REG_ISR)) ? 1 : 0);
+}
+
+static uint64_t
+a369kpd_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    A369KPDState *s = A369KPD(opaque);
+    uint64_t ret = 0;
+
+    switch (addr) {
+    case REG_CR ... REG_ASPR:
+        ret = s->regs[addr / 4];
+        break;
+    case REG_REVR:
+        ret = 0x00010403;  /* rev. = 1.4.3 */
+        break;
+    case REG_FEAR:
+        ret = 0x00000808;  /* 8x8 scan code for keypad */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "a369kpd: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+a369kpd_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    A369KPDState *s = A369KPD(opaque);
+
+    switch (addr) {
+    case REG_CR:
+        KBC_REG32(s, REG_CR) = (uint32_t)val;
+        /* if ftkbc010 enabled */
+        if (!(KBC_REG32(s, REG_CR) & CR_EN)) {
+            break;
+        }
+        /* if keypad interrupt cleared */
+        if (KBC_REG32(s, REG_CR) & CR_KPDIC) {
+            KBC_REG32(s, REG_CR) &= ~CR_KPDIC;
+            KBC_REG32(s, REG_ISR) &= ~ISR_KPDI;
+        }
+        /* if rx interrupt cleared */
+        if (KBC_REG32(s, REG_CR) & CR_RXICLR) {
+            KBC_REG32(s, REG_CR) &= ~CR_RXICLR;
+            KBC_REG32(s, REG_ISR) &= ~ISR_RXI;
+        }
+        /* if tx interrupt cleared */
+        if (KBC_REG32(s, REG_CR) & CR_TXICLR) {
+            KBC_REG32(s, REG_CR) &= ~CR_TXICLR;
+            KBC_REG32(s, REG_ISR) &= ~ISR_TXI;
+        }
+        a369kpd_update_irq(s);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "a369kpd: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = a369kpd_mem_read,
+    .write = a369kpd_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void a369kpd_key_event(void *opaque, int scancode)
+{
+    A369KPDState *s = A369KPD(opaque);
+    int x, y, released = 0;
+
+    /* key release from qemu */
+    if (scancode & 0x80) {
+        released = 1;
+    }
+
+    /* strip qemu key release bit */
+    scancode &= ~0x80;
+
+    /* keypad interrupt */
+    if (!released && (KBC_REG32(s, REG_CR) & CR_KPDEN)) {
+        switch (scancode) {
+        case KEYCODE_ESC:
+        case KEYCODE_BACKSPACE:
+            x = 1;
+            break;
+        case KEYCODE_ENTER:
+        case KEYCODE_MENU:
+        case KEYCODE_SPACE:
+            x = 3;
+            break;
+        default:
+            x = 2;    /* KEY_HOME */
+            break;
+        }
+        y = 0;
+        KBC_REG32(s, REG_KPDXR) = ~BIT(x);
+        KBC_REG32(s, REG_KPDYR) = ~BIT(y);
+        KBC_REG32(s, REG_ISR)  |= ISR_KPDI;
+        a369kpd_update_irq(s);
+    }
+}
+
+static void a369kpd_reset(DeviceState *ds)
+{
+    A369KPDState *s = A369KPD(SYS_BUS_DEVICE(ds));
+
+    memset(s->regs, 0, sizeof(s->regs));
+    KBC_REG32(s, REG_KPDXR) = 0xffffffff;
+    KBC_REG32(s, REG_KPDYR) = 0xffffffff;
+
+    qemu_irq_lower(s->irq);
+}
+
+static void a369kpd_realize(DeviceState *dev, Error **errp)
+{
+    A369KPDState *s = A369KPD(dev);
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_A369KPD,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+
+    qemu_add_kbd_event_handler(a369kpd_key_event, s);
+}
+
+static const VMStateDescription vmstate_ftkbc010 = {
+    .name = TYPE_A369KPD,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, A369KPDState, CFG_REGSIZE),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void a369kpd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc  = TYPE_A369KPD;
+    dc->vmsd  = &vmstate_ftkbc010;
+    dc->reset = a369kpd_reset;
+    dc->realize = a369kpd_realize;
+}
+
+static const TypeInfo a369kpd_info = {
+    .name          = TYPE_A369KPD,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(A369KPDState),
+    .class_init    = a369kpd_class_init,
+};
+
+static void a369kpd_register_types(void)
+{
+    type_register_static(&a369kpd_info);
+}
+
+type_init(a369kpd_register_types)
diff --git a/hw/arm/faraday_a369_scu.c b/hw/arm/faraday_a369_scu.c
new file mode 100644
index 0000000..82cc1c1
--- /dev/null
+++ b/hw/arm/faraday_a369_scu.c
@@ -0,0 +1,182 @@
+/*
+ * Faraday A369 SCU
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * The system control unit (SCU) is responsible for
+ * power, clock and pinmux management. Since most of
+ * the features are useless to QEMU, only partial clock
+ * and pinmux management are implemented as a set of R/W values.
+ *
+ * This code is licensed under GNU GPL v2+
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "sysemu/sysemu.h"
+
+#define REG_CHIPID      0x000   /* SoC chip id */
+#define REG_REVISON     0x004   /* SCU revision id */
+#define REG_HWCFG       0x008   /* HW configuration strap */
+#define REG_CPUMFCR     0x00C   /* CPUM (master) freq. control */
+#define REG_SCUCR       0x010   /* SCU control register */
+#define REG_SCUSR       0x014   /* SCU status register */
+#define REG_OSCCR       0x01C   /* OSC control register */
+#define REG_PLL1CR      0x020   /* PLL1 control register */
+#define REG_DLLCR       0x024   /* DLL control register */
+#define REG_SPR(n)      (0x100 + ((n) << 2)) /* Scratchpad register 0 - 15 */
+#define REG_GPINMUX     0x200   /* General PINMUX */
+#define REG_EXTHWCFG    0x204   /* Extended HW configuration strap */
+#define REG_CLKCFG0     0x228   /* Clock configuration 0 */
+#define REG_CLKCFG1     0x22C   /* Clock configuration 1 */
+#define REG_SCER        0x230   /* Special clock enable register */
+#define REG_MFPINMUX0   0x238   /* Multi-function pinmux 0 */
+#define REG_MFPINMUX1   0x23C   /* Multi-function pinmux 1 */
+#define REG_DCSRCR0     0x240   /* Driving cap. & Slew rate control 0 */
+#define REG_DCSRCR1     0x244   /* Driving cap. & Slew rate control 1 */
+#define REG_DCCR        0x254   /* Delay chain control register */
+#define REG_PCR         0x258   /* Power control register */
+
+#define TYPE_A369SCU    "a369.scu"
+#define CFG_REGSIZE     (0x260 / 4)
+
+typedef struct A369SCUState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    /* HW registers */
+    uint32_t regs[CFG_REGSIZE];
+} A369SCUState;
+
+#define A369SCU(obj) \
+    OBJECT_CHECK(A369SCUState, obj, TYPE_A369SCU)
+
+#define SCU_REG32(s, off) \
+    ((s)->regs[(off) / 4])
+
+static uint64_t
+a369scu_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    A369SCUState *s = A369SCU(opaque);
+    uint64_t ret = 0;
+
+    switch (addr) {
+    case 0x000 ... (CFG_REGSIZE - 1) * 4:
+        ret = s->regs[addr / 4];
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "a369scu: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+a369scu_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    A369SCUState *s = A369SCU(opaque);
+
+    switch (addr) {
+    case REG_GPINMUX:
+    case REG_CLKCFG0:
+    case REG_CLKCFG1:
+    case REG_MFPINMUX0:
+    case REG_MFPINMUX1:
+        s->regs[addr / 4] = (uint32_t)val;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "a369scu: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = a369scu_mem_read,
+    .write = a369scu_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void a369scu_reset(DeviceState *ds)
+{
+    A369SCUState *s = A369SCU(SYS_BUS_DEVICE(ds));
+
+    memset(s->regs, 0, sizeof(s->regs));
+
+    SCU_REG32(s, REG_CHIPID)    = 0x00003369; /* A369 */
+    SCU_REG32(s, REG_REVISON)   = 0x00010000; /* Rev. = 1.0.0 */
+    SCU_REG32(s, REG_HWCFG)     = 0x00000c10; /* CPU = 4 * HCLK */
+    SCU_REG32(s, REG_CPUMFCR)   = 0x00000230; /* CPU = 4 * HCLK */
+    SCU_REG32(s, REG_SCUCR)     = 0x00000083; /* no low power detect */
+    SCU_REG32(s, REG_SCUSR)     = 0x00000100; /* CPU freq. stable */
+    SCU_REG32(s, REG_OSCCR)     = 0x00000003; /* OSCH disabled */
+    SCU_REG32(s, REG_PLL1CR)    = 0x20010003; /* PLL_NS = 32 */
+    SCU_REG32(s, REG_DLLCR)     = 0x00000003; /* DLL enabled & stable */
+    SCU_REG32(s, REG_GPINMUX)   = 0x00001078; /* Pinmux */
+    SCU_REG32(s, REG_EXTHWCFG)  = 0x00001cc8; /* NAND flash boot */
+    SCU_REG32(s, REG_CLKCFG0)   = 0x26877330; /* LCD = HCLK */
+    SCU_REG32(s, REG_CLKCFG1)   = 0x000a0a0a; /* SD = HCLK, SPI=PCLK */
+    SCU_REG32(s, REG_SCER)      = 0x00003fff; /* All clock enabled */
+    SCU_REG32(s, REG_MFPINMUX0) = 0x00000241; /* Pinmux */
+    SCU_REG32(s, REG_MFPINMUX1) = 0x00000000; /* Pinmux */
+    SCU_REG32(s, REG_DCSRCR0)   = 0x11111111; /* Slow slew rate */
+    SCU_REG32(s, REG_DCSRCR1)   = 0x11111111; /* Slow slew rate */
+    SCU_REG32(s, REG_DCCR)      = 0x00000303; /* All delay chain = 3 */
+    SCU_REG32(s, REG_PCR)       = 0x8000007f; /* High performance mode */
+}
+
+static void a369scu_realize(DeviceState *dev, Error **errp)
+{
+    A369SCUState *s = A369SCU(dev);
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_A369SCU,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+}
+
+static const VMStateDescription vmstate_a369scu = {
+    .name = TYPE_A369SCU,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, A369SCUState, CFG_REGSIZE),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void a369scu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc  = TYPE_A369SCU;
+    dc->vmsd  = &vmstate_a369scu;
+    dc->reset = a369scu_reset;
+    dc->realize = a369scu_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo a369scu_info = {
+    .name          = TYPE_A369SCU,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(A369SCUState),
+    .class_init    = a369scu_class_init,
+};
+
+static void a369scu_register_types(void)
+{
+    type_register_static(&a369scu_info);
+}
+
+type_init(a369scu_register_types)
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
new file mode 100644
index 0000000..4e19c7e
--- /dev/null
+++ b/hw/arm/faraday_a369_soc.c
@@ -0,0 +1,190 @@
+/*
+ * Faraday A369 SoC
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/i2c.h"
+#include "hw/boards.h"
+#include "hw/flash.h"
+#include "hw/serial.h"
+#include "hw/ssi.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+
+#include "faraday.h"
+
+static void a369soc_reset(DeviceState *ds)
+{
+    int i;
+    uint64_t size;
+    FaradaySoCState *s = FARADAY_SOC(SYS_BUS_DEVICE(ds));
+
+    /* AHB slave base & window configuration */
+    memset(s->ahb_slave, 0, sizeof(s->ahb_slave));
+    s->ahb_slave[0] = 0x94050000;
+    s->ahb_slave[1] = 0x96040000;
+    s->ahb_slave[2] = 0x90f00000;
+    s->ahb_slave[3] = 0x92050000; /* APB: base=0x92000000, size=32MB */
+    s->ahb_slave[5] = 0xc0080000;
+    if (!s->bi) {   /* ROM emulation enabled */
+        s->ahb_slave[4] = 0x00080000; /* ROM: base=0x00000000, size=256MB */
+        s->ahb_slave[6] = 0x10090000; /* RAM: base=0x10000000, size=512MB */
+    } else {        /* Direct boot */
+        s->ahb_slave[4] = s->rom_base | 0x80000; /* ROM: size=256MB */
+        s->ahb_slave[6] = s->ram_base | 0x90000; /* RAM: size=512MB */
+    }
+    for (i = 0; i < 15; ++i) {
+        s->ahb_slave[7 + i] = 0x90000000 + (i << 20);
+    }
+    s->ahb_slave[22] = 0x40080000;
+    s->ahb_slave[23] = 0x60080000;
+    s->ahb_slave[24] = 0xa0000000; /* SRAM: base=0xA0000000, size=1MB */
+
+    /* APB slave base & window configuration */
+    memset(s->apb_slave, 0, sizeof(s->apb_slave));
+    for (i = 0; i < 18; ++i) {
+        s->apb_slave[i] = 0x12000000 + (i << 20);
+    }
+
+    /* ROM base = slave4 & 0x000fffff, size = 6KB */
+    s->rom_base = s->ahb_slave[4] & 0xfff00000;
+    s->rom_size = 6 << 10;
+
+    /* RAM base = slave6 & 0x000fffff, size <= (1 << slave6.BIT[19-16]) MB */
+    size = (1 << extract32(s->ahb_slave[6], 16, 4)) << 20;
+    s->ram_base = s->ahb_slave[6] & 0xfff00000;
+    if (!s->ram_size || s->ram_size > size) {
+        s->ram_size = size;
+    }
+}
+
+static void
+a369soc_device_init(FaradaySoCState *s)
+{
+    DriveInfo *dinfo;
+    DeviceState *ds;
+
+    s->as = get_system_memory();
+    s->ram = g_new(MemoryRegion, 1);
+    s->sram = g_new(MemoryRegion, 1);
+
+    /* CPU */
+    s->cpu = cpu_arm_init(!s->cpu_model ? "fa626te" : s->cpu_model);
+    if (!s->cpu) {
+        fprintf(stderr, "a369soc: Unable to find CPU definition\n");
+        abort();
+    }
+
+    /* RAM Init */
+    memory_region_init_ram(s->ram, "a369soc.ram", s->ram_size);
+    vmstate_register_ram_global(s->ram);
+
+    /* Embedded RAM Init */
+    memory_region_init_ram(s->sram, "a369soc.sram", 0x4000);
+    vmstate_register_ram_global(s->sram);
+    memory_region_add_subregion(s->as, 0xA0000000, s->sram);
+
+    /* Embedded ROM Init (Emulated with a parallel NOR flash) */
+    dinfo = drive_get_next(IF_PFLASH);
+    s->rom = pflash_cfi01_register(
+                    s->rom_base,
+                    NULL,
+                    "a369soc.rom",
+                    s->rom_size,
+                    dinfo ? dinfo->bdrv : NULL,
+                    1024,               /* 1 KB sector */
+                    s->rom_size >> 10,  /* sectors per chip */
+                    4,                  /* 32 bits */
+                    0, 0, 0, 0,         /* id */
+                    0                   /* Little Endian */);
+    if (!s->rom) {
+        fprintf(stderr, "a369soc: Unable to init ROM device.\n");
+        abort();
+    }
+
+    /* Serial (FTUART010 which is 16550A compatible) */
+    if (serial_hds[0]) {
+        serial_mm_init(s->as,
+                       0x92b00000,
+                       2,
+                       s->pic[53],
+                       18432000,
+                       serial_hds[0],
+                       DEVICE_LITTLE_ENDIAN);
+    }
+    if (serial_hds[1]) {
+        serial_mm_init(s->as,
+                       0x92c00000,
+                       2,
+                       s->pic[54],
+                       18432000,
+                       serial_hds[1],
+                       DEVICE_LITTLE_ENDIAN);
+    }
+
+    /* ftscu010 */
+    ds = sysbus_create_simple("a369.scu", 0x92000000, NULL);
+    s->scu = ds;
+
+    /* ftkbc010 */
+    ds = sysbus_create_simple("a369.kpd", 0x92f00000, s->pic[21]);
+}
+
+static void a369soc_realize(DeviceState *dev, Error **errp)
+{
+    FaradaySoCState *s = FARADAY_SOC(dev);
+
+    a369soc_reset(dev);
+    a369soc_device_init(s);
+}
+
+static Property a369soc_properties[] = {
+    DEFINE_PROP_STRING("cpu_model", FaradaySoCState, cpu_model),
+    DEFINE_PROP_UINT64("ram_size", FaradaySoCState, ram_size, 0x20000000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_a369soc = {
+    .name = TYPE_FARADAY_SOC,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void a369soc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc  = TYPE_FARADAY_SOC;
+    dc->vmsd  = &vmstate_a369soc;
+    dc->props = a369soc_properties;
+    dc->reset = a369soc_reset;
+    dc->realize = a369soc_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo a369soc_info = {
+    .name          = TYPE_FARADAY_SOC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(FaradaySoCState),
+    .class_init    = a369soc_class_init,
+};
+
+static void a369soc_register_types(void)
+{
+    type_register_static(&a369soc_info);
+}
+
+type_init(a369soc_register_types)
diff --git a/hw/arm/ftkbc010.h b/hw/arm/ftkbc010.h
new file mode 100644
index 0000000..43a77ad
--- /dev/null
+++ b/hw/arm/ftkbc010.h
@@ -0,0 +1,44 @@
+/*
+ * Faraday FTKBC010 Keyboard/Keypad Controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+
+ */
+#ifndef HW_ARM_FTKBC010_H
+#define HW_ARM_FTKBC010_H
+
+#include "qemu/bitops.h"
+
+#define REG_CR      0x00    /* control register */
+#define REG_SRDR    0x04    /* sample rate division register */
+#define REG_RSCR    0x08    /* request to send counter register */
+#define REG_SR      0x0C    /* status register */
+#define REG_ISR     0x10    /* interrupt status register */
+#define REG_KBDRR   0x14    /* keyboard receive register */
+#define REG_KBDTR   0x18    /* keyboard transmit register */
+#define REG_IMR     0x1C    /* interrupt mask register */
+#define REG_KPDXR   0x30    /* keypad X-Axis register */
+#define REG_KPDYR   0x34    /* keypad Y-Axis register */
+#define REG_ASPR    0x38    /* auto-scan period register */
+#define REG_REVR    0x50    /* revision register */
+#define REG_FEAR    0x54    /* feature register */
+
+#define CR_KPDIC    BIT(10) /* Write 1 to clear Keypad interupt */
+#define CR_KPDAS    BIT(9)  /* Keypad audo-scan enabled */
+#define CR_KPDEN    BIT(8)  /* Keypad function enabled */
+#define CR_RXICLR   BIT(7)  /* Write 1 to clear Keyboard/Mouse Rx interrupt */
+#define CR_TXICLR   BIT(6)  /* Write 1 to clear Keyboard/Mouse Tx interrupt */
+#define CR_NOLC     BIT(5)  /* No line control bit */
+#define CR_RXIEN    BIT(4)  /* Keyboard/Mouse Rx interrupt enabled */
+#define CR_TXIEN    BIT(3)  /* Keyboard/Mouse Tx interrupt enabled */
+#define CR_EN       BIT(2)  /* Chip enabled */
+#define CR_DATDN    BIT(1)  /* Data disabled */
+#define CR_CLKDN    BIT(0)  /* Clock disabled */
+
+#define ISR_KPDI    BIT(2)  /* Keypad interupt */
+#define ISR_TXI     BIT(1)  /* Keyboard/Mouse Tx interrupt enabled */
+#define ISR_RXI     BIT(0)  /* Keyboard/Mouse Rx interrupt enabled */
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 03/24] hw/arm: add FTINTC020 interrupt controller support
  2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 01/24] target-arm: add Faraday ARMv5TE processors support Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 02/24] hw/arm: add Faraday a369 SoC platform support Kuo-Jung Su
@ 2013-03-15 13:13 ` Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 04/24] hw/arm: add FTAHBC020 AHB " Kuo-Jung Su
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Blue Swirl, Paul Brook, Kuo-Jung Su,
	Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The FTINTC020 interrupt controller supports both FIQ and IRQ signals
to the microprocessor.
It can handle up to 64 configurable IRQ sources and 64 FIQ sources.
The output signals to the microprocessor can be configured as
level-high/low active or edge-rising/falling triggered.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs      |    1 +
 hw/arm/faraday_a369_soc.c |   11 ++
 hw/arm/ftintc020.c        |  302 +++++++++++++++++++++++++++++++++++++++++++++
 hw/arm/ftintc020.h        |   57 +++++++++
 4 files changed, 371 insertions(+)
 create mode 100644 hw/arm/ftintc020.c
 create mode 100644 hw/arm/ftintc020.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 104e0e7..536d6cf 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -37,3 +37,4 @@ obj-y += omap1.o omap2.o
 
 obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
             faraday_a369_kpd.o
+obj-y += ftintc020.o
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index 4e19c7e..eab05dc 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -72,6 +72,8 @@ a369soc_device_init(FaradaySoCState *s)
 {
     DriveInfo *dinfo;
     DeviceState *ds;
+    qemu_irq *cpu_pic;
+    int i;
 
     s->as = get_system_memory();
     s->ram = g_new(MemoryRegion, 1);
@@ -111,6 +113,15 @@ a369soc_device_init(FaradaySoCState *s)
         abort();
     }
 
+    /* Interrupt Controller */
+    cpu_pic = arm_pic_init_cpu(s->cpu);
+    ds = sysbus_create_varargs("ftintc020", 0x90100000,
+                               cpu_pic[ARM_PIC_CPU_IRQ],
+                               cpu_pic[ARM_PIC_CPU_FIQ], NULL);
+    for (i = 0; i < ARRAY_SIZE(s->pic); ++i) {
+        s->pic[i] = qdev_get_gpio_in(ds, i);
+    }
+
     /* Serial (FTUART010 which is 16550A compatible) */
     if (serial_hds[0]) {
         serial_mm_init(s->as,
diff --git a/hw/arm/ftintc020.c b/hw/arm/ftintc020.c
new file mode 100644
index 0000000..1a476d3
--- /dev/null
+++ b/hw/arm/ftintc020.c
@@ -0,0 +1,302 @@
+/*
+ * Faraday FTINTC020 Programmable Interrupt Controller.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+
+#include "ftintc020.h"
+
+#define TYPE_FTINTC020  "ftintc020"
+
+#define CFG_REGSIZE     (0x100 / 4)
+
+typedef struct Ftintc020State {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    qemu_irq irq;
+    qemu_irq fiq;
+
+    uint32_t irq_ps[2]; /* IRQ pin state */
+    uint32_t fiq_ps[2]; /* FIQ pin state */
+
+    /* HW register caches */
+    uint32_t regs[CFG_REGSIZE];
+} Ftintc020State;
+
+#define FTINTC020(obj) \
+    OBJECT_CHECK(Ftintc020State, obj, TYPE_FTINTC020)
+
+#define PIC_REG32(s, off) \
+    ((s)->regs[(off) / 4])
+
+#define IRQ_REG32(s, n, off) \
+    ((s)->regs[(REG_IRQ(n) + ((off) & REG_MASK)) / 4])
+
+#define FIQ_REG32(s, n, off) \
+    ((s)->regs[(REG_FIQ(n) + ((off) & REG_MASK)) / 4])
+
+static void
+ftintc020_update_irq(Ftintc020State *s)
+{
+    uint32_t mask[2];
+
+    /* FIQ */
+    mask[0] = PIC_REG32(s, REG_FIQ32SRC) & PIC_REG32(s, REG_FIQ32ENA);
+    mask[1] = PIC_REG32(s, REG_FIQ64SRC) & PIC_REG32(s, REG_FIQ64ENA);
+    qemu_set_irq(s->fiq, !!(mask[0] || mask[1]));
+
+    /* IRQ */
+    mask[0] = PIC_REG32(s, REG_IRQ32SRC) & PIC_REG32(s, REG_IRQ32ENA);
+    mask[1] = PIC_REG32(s, REG_IRQ64SRC) & PIC_REG32(s, REG_IRQ64ENA);
+    qemu_set_irq(s->irq, !!(mask[0] || mask[1]));
+}
+
+/* Note: Here level means state of the signal on a pin */
+static void
+ftintc020_set_irq(void *opaque, int irq, int level)
+{
+    Ftintc020State *s = FTINTC020(opaque);
+    uint32_t i = irq / 32;
+    uint32_t mask = BIT(irq & 0x1f);
+
+    switch (irq) {
+    case 0  ... 63:
+        /* IRQ */
+        if (IRQ_REG32(s, irq, REG_MDR) & mask) {
+            /* Edge Triggered */
+            if (IRQ_REG32(s, irq, REG_LVR) & mask) {
+                /* Falling Active */
+                if ((s->irq_ps[i] & mask) && !level) {
+                    IRQ_REG32(s, irq, REG_SRC) |= mask;
+                }
+            } else {
+                /* Rising Active */
+                if (!(s->irq_ps[i] & mask) && level) {
+                    IRQ_REG32(s, irq, REG_SRC) |= mask;
+                }
+            }
+        } else {
+            /* Level Triggered */
+            if (IRQ_REG32(s, irq, REG_LVR) & mask) {
+                /* Low Active */
+                if (level) {
+                    IRQ_REG32(s, irq, REG_SRC) &= ~mask;
+                } else {
+                    IRQ_REG32(s, irq, REG_SRC) |= mask;
+                }
+            } else {
+                /* High Active */
+                if (level) {
+                    IRQ_REG32(s, irq, REG_SRC) |= mask;
+                } else {
+                    IRQ_REG32(s, irq, REG_SRC) &= ~mask;
+                }
+            }
+        }
+
+        /* FIQ */
+        if (FIQ_REG32(s, irq, REG_MDR) & mask) {
+            /* Edge Triggered */
+            if (FIQ_REG32(s, irq, REG_LVR) & mask) {
+                /* Falling Active */
+                if ((s->fiq_ps[i] & mask) && !level) {
+                    FIQ_REG32(s, irq, REG_SRC) |= mask;
+                }
+            } else {
+                /* Rising Active */
+                if (!(s->fiq_ps[i] & mask) && level) {
+                    FIQ_REG32(s, irq, REG_SRC) |= mask;
+                }
+            }
+        } else {
+            /* Level Triggered */
+            if (FIQ_REG32(s, irq, REG_LVR) & mask) {
+                /* Low Active */
+                if (level) {
+                    FIQ_REG32(s, irq, REG_SRC) &= ~mask;
+                } else {
+                    FIQ_REG32(s, irq, REG_SRC) |= mask;
+                }
+            } else {
+                /* High Active */
+                if (level) {
+                    FIQ_REG32(s, irq, REG_SRC) |= mask;
+                } else {
+                    FIQ_REG32(s, irq, REG_SRC) &= ~mask;
+                }
+            }
+        }
+        /* update IRQ/FIQ pin states */
+        if (level) {
+            s->irq_ps[i] |= mask;
+            s->fiq_ps[i] |= mask;
+        } else {
+            s->irq_ps[i] &= ~mask;
+            s->fiq_ps[i] &= ~mask;
+        }
+        break;
+
+    default:
+        fprintf(stderr, "ftintc020: undefined irq=%d\n", irq);
+        abort();
+    }
+
+    ftintc020_update_irq(s);
+}
+
+static uint64_t
+ftintc020_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    Ftintc020State *s = FTINTC020(opaque);
+    uint32_t ret = 0;
+
+    if (addr > REG_FIQ64SR) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftintc020: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        return ret;
+    }
+
+    switch (addr) {
+    case REG_IRQ32SR:
+        ret = PIC_REG32(s, REG_IRQ32SRC) & PIC_REG32(s, REG_IRQ32ENA);
+        break;
+    case REG_IRQ64SR:
+        ret = PIC_REG32(s, REG_IRQ64SRC) & PIC_REG32(s, REG_IRQ64ENA);
+        break;
+    case REG_FIQ32SR:
+        ret = PIC_REG32(s, REG_FIQ32SRC) & PIC_REG32(s, REG_FIQ32ENA);
+        break;
+    case REG_FIQ64SR:
+        ret = PIC_REG32(s, REG_FIQ64SRC) & PIC_REG32(s, REG_FIQ64ENA);
+        break;
+    default:
+        ret = s->regs[addr / 4];
+        break;
+    }
+
+    return ret;
+}
+
+static void
+ftintc020_mem_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
+{
+    Ftintc020State *s = FTINTC020(opaque);
+
+    if (addr > REG_FIQ64SR) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftintc020: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        return;
+    }
+
+    switch (addr) {
+    case REG_IRQ32SCR:
+        /* clear edge triggered interrupts only */
+        value = ~(value & PIC_REG32(s, REG_IRQ32MDR));
+        PIC_REG32(s, REG_IRQ32SRC) &= (uint32_t)value;
+        break;
+    case REG_IRQ64SCR:
+        /* clear edge triggered interrupts only */
+        value = ~(value & PIC_REG32(s, REG_IRQ64MDR));
+        PIC_REG32(s, REG_IRQ64SRC) &= (uint32_t)value;
+        break;
+    case REG_FIQ32SCR:
+        /* clear edge triggered interrupts only */
+        value = ~(value & PIC_REG32(s, REG_FIQ32MDR));
+        PIC_REG32(s, REG_FIQ32SRC) &= (uint32_t)value;
+        break;
+    case REG_FIQ64SCR:
+        /* clear edge triggered interrupts only */
+        value = ~(value & PIC_REG32(s, REG_FIQ64MDR));
+        PIC_REG32(s, REG_FIQ64SRC) &= (uint32_t)value;
+        break;
+    default:
+        s->regs[addr / 4] = (uint32_t)value;
+        break;
+    }
+
+    ftintc020_update_irq(s);
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = ftintc020_mem_read,
+    .write = ftintc020_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void ftintc020_reset(DeviceState *ds)
+{
+    Ftintc020State *s = FTINTC020(SYS_BUS_DEVICE(ds));
+
+    s->irq_ps[0] = 0;
+    s->irq_ps[1] = 0;
+    s->fiq_ps[0] = 0;
+    s->fiq_ps[1] = 0;
+    memset(s->regs, 0, sizeof(s->regs));
+
+    ftintc020_update_irq(s);
+}
+
+static VMStateDescription vmstate_ftintc020 = {
+    .name = TYPE_FTINTC020,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, Ftintc020State, CFG_REGSIZE),
+        VMSTATE_UINT32_ARRAY(irq_ps, Ftintc020State, 2),
+        VMSTATE_UINT32_ARRAY(fiq_ps, Ftintc020State, 2),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static void ftintc020_realize(DeviceState *dev, Error **errp)
+{
+    Ftintc020State *s = FTINTC020(dev);
+
+    /* Enable IC memory-mapped registers access.  */
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_FTINTC020,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+
+    qdev_init_gpio_in(&s->busdev.qdev, ftintc020_set_irq, 64);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->fiq);
+}
+
+static void ftintc020_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd    = &vmstate_ftintc020;
+    dc->reset   = ftintc020_reset;
+    dc->realize = ftintc020_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftintc020_info = {
+    .name          = TYPE_FTINTC020,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Ftintc020State),
+    .class_init    = ftintc020_class_init,
+};
+
+static void ftintc020_register_types(void)
+{
+    type_register_static(&ftintc020_info);
+}
+
+type_init(ftintc020_register_types)
diff --git a/hw/arm/ftintc020.h b/hw/arm/ftintc020.h
new file mode 100644
index 0000000..20d300c
--- /dev/null
+++ b/hw/arm/ftintc020.h
@@ -0,0 +1,57 @@
+/*
+ * Faraday FTINTC020 Programmable Interrupt Controller.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#ifndef HW_ARM_FTINTC020_H
+#define HW_ARM_FTINTC020_H
+
+#include "qemu/bitops.h"
+
+/* IRQ/FIO: 0 ~ 31 */
+#define REG_IRQ32SRC    0x00    /* IRQ source register */
+#define REG_IRQ32ENA    0x04    /* IRQ enable register */
+#define REG_IRQ32SCR    0x08    /* IRQ status clear register */
+#define REG_IRQ32MDR    0x0C    /* IRQ trigger mode register */
+#define REG_IRQ32LVR    0x10    /* IRQ trigger level register */
+#define REG_IRQ32SR     0x14    /* IRQ status register */
+
+#define REG_FIQ32SRC    0x20    /* FIQ source register */
+#define REG_FIQ32ENA    0x24    /* FIQ enable register */
+#define REG_FIQ32SCR    0x28    /* FIQ status clear register */
+#define REG_FIQ32MDR    0x2C    /* FIQ trigger mode register */
+#define REG_FIQ32LVR    0x30    /* FIQ trigger level register */
+#define REG_FIQ32SR     0x34    /* FIQ status register */
+
+/* Extended IRQ/FIO: 32 ~ 63 */
+#define REG_IRQ64SRC    0x60    /* Extended IRQ source register */
+#define REG_IRQ64ENA    0x64    /* Extended IRQ enable register */
+#define REG_IRQ64SCR    0x68    /* Extended IRQ status clear register */
+#define REG_IRQ64MDR    0x6C    /* Extended IRQ trigger mode register */
+#define REG_IRQ64LVR    0x70    /* Extended IRQ trigger level register */
+#define REG_IRQ64SR     0x74    /* Extended IRQ status register */
+
+#define REG_FIQ64SRC    0x80    /* Extended FIQ source register */
+#define REG_FIQ64ENA    0x84    /* Extended FIQ enable register */
+#define REG_FIQ64SCR    0x88    /* Extended FIQ status clear register */
+#define REG_FIQ64MDR    0x8C    /* Extended FIQ trigger mode register */
+#define REG_FIQ64LVR    0x90    /* Extended FIQ trigger level register */
+#define REG_FIQ64SR     0x94    /* Extended FIQ status register */
+
+/* Common register offset to IRQ/FIQ */
+#define REG_SRC         0x00    /* Source register */
+#define REG_ENA         0x04    /* Enable register */
+#define REG_SCR         0x08    /* Status clear register */
+#define REG_MDR         0x0C    /* Trigger mode register */
+#define REG_LVR         0x10    /* Trigger level register */
+#define REG_SR          0x14    /* Status register */
+#define REG_MASK        0x1f
+
+#define REG_IRQ(n)      (((n) < 32) ? REG_IRQ32SRC : REG_IRQ64SRC)
+#define REG_FIQ(n)      (((n) < 32) ? REG_FIQ32SRC : REG_FIQ64SRC)
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 04/24] hw/arm: add FTAHBC020 AHB controller support
  2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
                   ` (2 preceding siblings ...)
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 03/24] hw/arm: add FTINTC020 interrupt controller support Kuo-Jung Su
@ 2013-03-15 13:13 ` Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII " Kuo-Jung Su
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Blue Swirl, Paul Brook, Kuo-Jung Su,
	Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

It's used to perform AHB remap and QEMU RAM initialization
when the SDRAM is initialized before AHB remap process activated.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs      |    1 +
 hw/arm/faraday_a369_soc.c |   10 +++
 hw/arm/ftahbc020.c        |  202 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+)
 create mode 100644 hw/arm/ftahbc020.c

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 536d6cf..af36b01 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -38,3 +38,4 @@ obj-y += omap1.o omap2.o
 obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
             faraday_a369_kpd.o
 obj-y += ftintc020.o
+obj-y += ftahbc020.o
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index eab05dc..01b4395 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -70,6 +70,7 @@ static void a369soc_reset(DeviceState *ds)
 static void
 a369soc_device_init(FaradaySoCState *s)
 {
+    Error *local_errp = NULL;
     DriveInfo *dinfo;
     DeviceState *ds;
     qemu_irq *cpu_pic;
@@ -148,6 +149,15 @@ a369soc_device_init(FaradaySoCState *s)
 
     /* ftkbc010 */
     ds = sysbus_create_simple("a369.kpd", 0x92f00000, s->pic[21]);
+
+    /* ftahbc020 */
+    ds = sysbus_create_simple("ftahbc020", 0x94000000, NULL);
+    s->ahbc = ds;
+    object_property_set_link(OBJECT(ds), OBJECT(s), "soc", &local_errp);
+    if (local_errp) {
+        fprintf(stderr, "a369soc: Unable to set soc link for FTAHBC020\n");
+        abort();
+    }
 }
 
 static void a369soc_realize(DeviceState *dev, Error **errp)
diff --git a/hw/arm/ftahbc020.c b/hw/arm/ftahbc020.c
new file mode 100644
index 0000000..5681906
--- /dev/null
+++ b/hw/arm/ftahbc020.c
@@ -0,0 +1,202 @@
+/*
+ * Faraday AHB controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "sysemu/sysemu.h"
+
+#include "faraday.h"
+
+#define REG_SLAVE(n)    ((n) * 4) /* Slave config (base & size) */
+#define REG_PRIR        0x80    /* Priority register */
+#define REG_IDLECR      0x84    /* IDLE count register */
+#define REG_CR          0x88    /* Control register */
+#define REG_REVR        0x8c    /* Revision register */
+
+#define CR_REMAP        0x01    /* Enable AHB remap for slave 4 & 6 */
+
+#define TYPE_FTAHBC020  "ftahbc020"
+
+typedef struct Ftahbc020State {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    FaradaySoCState *soc;
+    /* HW register cache */
+    uint32_t cr;
+} Ftahbc020State;
+
+#define FTAHBC020(obj) \
+    OBJECT_CHECK(Ftahbc020State, obj, TYPE_FTAHBC020)
+
+static uint64_t
+ftahbc020_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    Ftahbc020State *s = FTAHBC020(opaque);
+    uint64_t ret = 0;
+
+    switch (addr) {
+    /* slave address & window configuration */
+    case REG_SLAVE(0) ... REG_SLAVE(3):
+    /* fall-through - skip slave4 */
+    case REG_SLAVE(5):
+    /* fall-through - skip slave6 */
+    case REG_SLAVE(7) ... REG_SLAVE(31):
+        ret = s->soc->ahb_slave[addr / 4];
+        break;
+    case REG_SLAVE(4):
+        ret = s->soc->rom_base | (s->soc->ahb_slave[4] & 0x000f0000);
+        break;
+    case REG_SLAVE(6):
+        ret = s->soc->ram_base | (s->soc->ahb_slave[6] & 0x000f0000);
+        break;
+    /* control register */
+    case REG_CR:
+        if (s->soc->ahb_remapped) {
+            s->cr |= CR_REMAP;
+        }
+        ret = s->cr;
+        break;
+    case REG_REVR:
+        ret = 0x00010301;   /* rev. 1.3.1 */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftahbc020: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+ftahbc020_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    Ftahbc020State *s = FTAHBC020(opaque);
+
+    switch (addr) {
+    case REG_CR:    /* control register */
+        s->cr = (uint32_t)val;
+        if (s->soc->ahb_remapped && !(s->cr & CR_REMAP)) {
+            fprintf(stderr, "ftahbc020: Once AHB remap is enabled, "
+                     "it could not be disabled!\n");
+            abort();
+        }
+        if (!s->soc->ahb_remapped && (s->cr & CR_REMAP)) {
+            /* Remap AHB slave 4 (ROM) & slave 6 (RAM) */
+            /* 1. Remap RAM to base of ROM */
+            s->soc->ram_base = s->soc->ahb_slave[4] & 0xfff00000;
+            /* 2. Remap ROM to base of ROM + size of RAM */
+            s->soc->rom_base = s->soc->ram_base
+                + ((1 << extract32(s->soc->ahb_slave[6], 16, 4)) << 20);
+            /* 3. Update ROM memory map */
+            sysbus_mmio_map(SYS_BUS_DEVICE(s->soc->rom), 0, s->soc->rom_base);
+            /* 4. Update RAM memory map if it has been initialized. */
+            if (s->soc->ddr_inited) {
+                memory_region_del_subregion(s->soc->as, s->soc->ram);
+                memory_region_add_subregion(s->soc->as, s->soc->ram_base,
+                                            s->soc->ram);
+            }
+            s->soc->ahb_remapped = true;
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftahbc020: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = ftahbc020_mem_read,
+    .write = ftahbc020_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void ftahbc020_reset(DeviceState *ds)
+{
+    Ftahbc020State *s = FTAHBC020(SYS_BUS_DEVICE(ds));
+    Error *local_errp = NULL;
+
+    s->soc = FARADAY_SOC(object_property_get_link(OBJECT(s),
+                                                  "soc",
+                                                  &local_errp));
+    if (local_errp) {
+        fprintf(stderr, "ftahbc020: Unable to get soc link\n");
+        abort();
+    }
+
+    if (s->soc->ahb_remapped && !s->soc->bi) {
+        s->soc->rom_base = s->soc->ahb_slave[4] & 0xfff00000;
+        s->soc->ram_base = s->soc->ahb_slave[6] & 0xfff00000;
+        sysbus_mmio_map(SYS_BUS_DEVICE(s->soc->rom), 0, s->soc->rom_base);
+        s->soc->ahb_remapped = false;
+    }
+
+    s->cr = 0;
+}
+
+static void ftahbc020_realize(DeviceState *dev, Error **errp)
+{
+    Ftahbc020State *s = FTAHBC020(dev);
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_FTAHBC020,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+
+    object_property_add_link(OBJECT(dev),
+                             "soc",
+                             TYPE_FARADAY_SOC,
+                             (Object **) &s->soc,
+                             errp);
+}
+
+static const VMStateDescription vmstate_ftahbc020 = {
+    .name = TYPE_FTAHBC020,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cr, Ftahbc020State),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void ftahbc020_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc  = TYPE_FTAHBC020;
+    dc->vmsd  = &vmstate_ftahbc020;
+    dc->reset = ftahbc020_reset;
+    dc->realize = ftahbc020_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftahbc020_info = {
+    .name          = TYPE_FTAHBC020,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Ftahbc020State),
+    .class_init    = ftahbc020_class_init,
+};
+
+static void ftahbc020_register_types(void)
+{
+    type_register_static(&ftahbc020_info);
+}
+
+type_init(ftahbc020_register_types)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support
  2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
                   ` (3 preceding siblings ...)
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 04/24] hw/arm: add FTAHBC020 AHB " Kuo-Jung Su
@ 2013-03-15 13:13 ` Kuo-Jung Su
  2013-03-16  3:32   ` Peter Crosthwaite
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 06/24] hw/arm: add FTPWMTMR010 timer support Kuo-Jung Su
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Blue Swirl, Paul Brook, Kuo-Jung Su,
	Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The FTDDRII030 is a DDRII SDRAM controller which is responsible for
SDRAM initialization.
In QEMU we emulate only the SDRAM enable function.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs      |    1 +
 hw/arm/faraday_a369_soc.c |    9 +++
 hw/arm/ftddrii030.c       |  183 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 hw/arm/ftddrii030.c

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index af36b01..0bbf838 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -39,3 +39,4 @@ obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
             faraday_a369_kpd.o
 obj-y += ftintc020.o
 obj-y += ftahbc020.o
+obj-y += ftddrii030.o
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index 01b4395..e8a63bb 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -158,6 +158,15 @@ a369soc_device_init(FaradaySoCState *s)
         fprintf(stderr, "a369soc: Unable to set soc link for FTAHBC020\n");
         abort();
     }
+
+    /* ftddrii030 */
+    ds = sysbus_create_simple("ftddrii030", 0x93100000, NULL);
+    s->ddrc = ds;
+    object_property_set_link(OBJECT(ds), OBJECT(s), "soc", &local_errp);
+    if (local_errp) {
+        fprintf(stderr, "a369soc: Unable to set soc link for FTDDRII030\n");
+        abort();
+    }
 }
 
 static void a369soc_realize(DeviceState *dev, Error **errp)
diff --git a/hw/arm/ftddrii030.c b/hw/arm/ftddrii030.c
new file mode 100644
index 0000000..90a5842
--- /dev/null
+++ b/hw/arm/ftddrii030.c
@@ -0,0 +1,183 @@
+/*
+ * Faraday DDRII controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "sysemu/sysemu.h"
+
+#include "faraday.h"
+
+#define REG_MCR             0x00    /* memory configuration register */
+#define REG_MSR             0x04    /* memory status register */
+#define REG_REVR            0x50    /* revision register */
+
+#define MSR_INIT_OK         BIT(8)  /* DDR2 initial is completed */
+#define MSR_CMD_MRS         BIT(0)  /* start MRS command */
+
+#define CFG_REGSIZE         (0x50 / 4)
+
+#define TYPE_FTDDRII030     "ftddrii030"
+
+typedef struct Ftddrii030State {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    FaradaySoCState *soc;
+    /* HW register cache */
+    uint32_t regs[CFG_REGSIZE];
+} Ftddrii030State;
+
+#define FTDDRII030(obj) \
+    OBJECT_CHECK(Ftddrii030State, obj, TYPE_FTDDRII030)
+
+#define DDR_REG32(s, off) \
+    ((s)->regs[(off) / 4])
+
+static uint64_t
+ftddrii030_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    Ftddrii030State *s = FTDDRII030(opaque);
+    uint64_t ret = 0;
+
+    if (s->soc->ddr_inited) {
+        DDR_REG32(s, REG_MSR) |= MSR_INIT_OK;
+    }
+
+    switch (addr) {
+    case REG_MCR ... (CFG_REGSIZE - 1) * 4:
+        ret = s->regs[addr / 4];
+        break;
+    case REG_REVR:
+        ret = 0x100;    /* rev. = 0.1.0 */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftddrii030: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+ftddrii030_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    Ftddrii030State *s = FTDDRII030(opaque);
+
+    switch (addr) {
+    case REG_MCR:
+        DDR_REG32(s, REG_MCR) = (uint32_t)val & 0xffff;
+        break;
+    case REG_MSR:
+        val = (val & 0x3f) | (DDR_REG32(s, REG_MSR) & MSR_INIT_OK);
+        if (!s->soc->ddr_inited && (val & MSR_CMD_MRS)) {
+            val &= ~MSR_CMD_MRS;
+            val |= MSR_INIT_OK;
+            memory_region_add_subregion(s->soc->as,
+                                        s->soc->ram_base,
+                                        s->soc->ram);
+            s->soc->ddr_inited = true;
+        }
+        DDR_REG32(s, REG_MSR) = (uint32_t)val;
+        break;
+    case 0x08 ... (CFG_REGSIZE - 1) * 4: /* DDRII Timing, ECC ...etc. */
+        s->regs[addr / 4] = (uint32_t)val;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftddrii030: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = ftddrii030_mem_read,
+    .write = ftddrii030_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void ftddrii030_reset(DeviceState *ds)
+{
+    Ftddrii030State *s = FTDDRII030(SYS_BUS_DEVICE(ds));
+    Error *local_errp = NULL;
+
+    s->soc = FARADAY_SOC(object_property_get_link(OBJECT(s),
+                                                  "soc",
+                                                  &local_errp));
+    if (local_errp) {
+        fprintf(stderr, "ftahbc020: Unable to get soc link\n");
+        abort();
+    }
+
+    if (s->soc->ddr_inited && !s->soc->bi) {
+        memory_region_del_subregion(s->soc->as, s->soc->ram);
+        s->soc->ddr_inited = false;
+    }
+
+    memset(s->regs, 0, sizeof(s->regs));
+}
+
+static void ftddrii030_realize(DeviceState *dev, Error **errp)
+{
+    Ftddrii030State *s = FTDDRII030(dev);
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_FTDDRII030,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+
+    object_property_add_link(OBJECT(dev),
+                             "soc",
+                             TYPE_FARADAY_SOC,
+                             (Object **) &s->soc,
+                             errp);
+}
+
+static const VMStateDescription vmstate_ftddrii030 = {
+    .name = TYPE_FTDDRII030,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, Ftddrii030State, CFG_REGSIZE),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void ftddrii030_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc  = TYPE_FTDDRII030;
+    dc->vmsd  = &vmstate_ftddrii030;
+    dc->reset = ftddrii030_reset;
+    dc->realize = ftddrii030_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftddrii030_info = {
+    .name          = TYPE_FTDDRII030,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Ftddrii030State),
+    .class_init    = ftddrii030_class_init,
+};
+
+static void ftddrii030_register_types(void)
+{
+    type_register_static(&ftddrii030_info);
+}
+
+type_init(ftddrii030_register_types)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 06/24] hw/arm: add FTPWMTMR010 timer support
  2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
                   ` (4 preceding siblings ...)
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII " Kuo-Jung Su
@ 2013-03-15 13:13 ` Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 07/24] hw/arm: add FTWDT010 watchdog " Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 08/24] hw/arm: add FTRTC011 RTC " Kuo-Jung Su
  7 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Blue Swirl, Paul Brook, Kuo-Jung Su,
	Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The FTPWMTMR010 is an APB device which provides up to 8 independent timers.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs      |    1 +
 hw/arm/faraday_a369_soc.c |   10 ++
 hw/arm/ftpwmtmr010.c      |  258 +++++++++++++++++++++++++++++++++++++++++++++
 hw/arm/ftpwmtmr010.h      |   31 ++++++
 4 files changed, 300 insertions(+)
 create mode 100644 hw/arm/ftpwmtmr010.c
 create mode 100644 hw/arm/ftpwmtmr010.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 0bbf838..bc18e22 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -40,3 +40,4 @@ obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
 obj-y += ftintc020.o
 obj-y += ftahbc020.o
 obj-y += ftddrii030.o
+obj-y += ftpwmtmr010.o
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index e8a63bb..874dc74 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -167,6 +167,16 @@ a369soc_device_init(FaradaySoCState *s)
         fprintf(stderr, "a369soc: Unable to set soc link for FTDDRII030\n");
         abort();
     }
+
+    /* Timer */
+    ds = qdev_create(NULL, "ftpwmtmr010");
+    qdev_prop_set_uint32(ds, "freq", 66 * 1000000);
+    qdev_init_nofail(ds);
+    sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, 0x92300000);
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 0, s->pic[8]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 1, s->pic[9]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 2, s->pic[10]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 3, s->pic[11]);
 }
 
 static void a369soc_realize(DeviceState *dev, Error **errp)
diff --git a/hw/arm/ftpwmtmr010.c b/hw/arm/ftpwmtmr010.c
new file mode 100644
index 0000000..c212cfe
--- /dev/null
+++ b/hw/arm/ftpwmtmr010.c
@@ -0,0 +1,258 @@
+/*
+ * Faraday FTPWMTMR010 Timer.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+#include "ftpwmtmr010.h"
+
+#define TYPE_FTPWMTMR010        "ftpwmtmr010"
+#define TYPE_FTPWMTMR010_TIMER  "ftpwmtmr010_timer"
+
+typedef struct Ftpwmtmr010State Ftpwmtmr010State;
+
+typedef struct Ftpwmtmr010Timer {
+    uint32_t ctrl;
+    uint32_t cntb;
+    int id;
+    uint64_t timeout;
+    uint64_t countdown;
+    qemu_irq irq;
+    QEMUTimer *qtimer;
+    Ftpwmtmr010State *chip;
+} Ftpwmtmr010Timer;
+
+struct Ftpwmtmr010State {
+    SysBusDevice busdev;
+
+    MemoryRegion iomem;
+    Ftpwmtmr010Timer timer[8];
+    uint32_t freq;        /* desired source clock */
+    uint64_t step;        /* get_ticks_per_sec() / freq */
+    uint32_t stat;
+};
+
+#define FTPWMTMR010(obj) \
+    OBJECT_CHECK(Ftpwmtmr010State, obj, TYPE_FTPWMTMR010)
+
+static uint64_t
+ftpwmtmr010_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    Ftpwmtmr010State *s = FTPWMTMR010(opaque);
+    Ftpwmtmr010Timer *t;
+    uint64_t now = qemu_get_clock_ns(vm_clock);
+    uint64_t ret = 0;
+
+    switch (addr) {
+    case REG_SR:
+        ret = s->stat;
+        break;
+    case REG_REVR:
+        ret = 0x00000000;   /* Rev. 0.0.0 (no rev. id) */
+        break;
+    case REG_TIMER_BASE(1) ... REG_TIMER_BASE(8) + 0x0C:
+        t = s->timer + (addr >> 4) - 1;
+        switch (addr & 0x0f) {
+        case REG_TIMER_CTRL:
+            return t->ctrl;
+        case REG_TIMER_CNTB:
+            return t->cntb;
+        case REG_TIMER_CNTO:
+            if ((t->ctrl & TIMER_CTRL_START) && (t->timeout > now)) {
+                ret = (t->timeout - now) / s->step;
+            }
+            break;
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftpwmtmr010: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+ftpwmtmr010_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    Ftpwmtmr010State *s = FTPWMTMR010(opaque);
+    Ftpwmtmr010Timer *t;
+    int i;
+
+    switch (addr) {
+    case REG_SR:
+        s->stat &= ~((uint32_t)val);
+        for (i = 0; i < 8; ++i) {
+            if (val & BIT(i)) {
+                qemu_irq_lower(s->timer[i].irq);
+            }
+        }
+        break;
+    case REG_TIMER_BASE(1) ... REG_TIMER_BASE(8) + 0x0C:
+        t = s->timer + (addr >> 4) - 1;
+        switch (addr & 0x0f) {
+        case REG_TIMER_CTRL:
+            t->ctrl = (uint32_t)val;
+            if (t->ctrl & TIMER_CTRL_UPDATE) {
+                t->countdown = (uint64_t)t->cntb * s->step;
+            }
+            if (t->ctrl & TIMER_CTRL_START) {
+                t->timeout = t->countdown + qemu_get_clock_ns(vm_clock);
+                qemu_mod_timer(t->qtimer, t->timeout);
+            }
+            break;
+        case REG_TIMER_CNTB:
+            t->cntb = (uint32_t)val;
+            break;
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftpwmtmr010: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = ftpwmtmr010_mem_read,
+    .write = ftpwmtmr010_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void ftpwmtmr010_timer_tick(void *opaque)
+{
+    Ftpwmtmr010Timer *t = opaque;
+    Ftpwmtmr010State *s = t->chip;
+
+    /* if the timer has been enabled/started */
+    if (!(t->ctrl & TIMER_CTRL_START)) {
+        return;
+    }
+
+    /* if the interrupt enabled */
+    if (t->ctrl & TIMER_CTRL_INTR) {
+        s->stat |= BIT(t->id);
+        if (t->ctrl & TIMER_CTRL_INTR_EDGE) {
+            qemu_irq_pulse(t->irq);
+        } else {
+            qemu_irq_raise(t->irq);
+        }
+    }
+
+    /* if auto-reload is enabled */
+    if (t->ctrl & TIMER_CTRL_AUTORELOAD) {
+        t->timeout = t->countdown + qemu_get_clock_ns(vm_clock);
+        qemu_mod_timer(t->qtimer, t->timeout);
+    } else {
+        t->ctrl &= ~TIMER_CTRL_START;
+    }
+}
+
+static void ftpwmtmr010_reset(DeviceState *ds)
+{
+    Ftpwmtmr010State *s = FTPWMTMR010(SYS_BUS_DEVICE(ds));
+    int i;
+
+    s->stat = 0;
+
+    for (i = 0; i < 8; ++i) {
+        s->timer[i].ctrl = 0;
+        s->timer[i].cntb = 0;
+        s->timer[i].timeout = 0;
+        qemu_irq_lower(s->timer[i].irq);
+        qemu_del_timer(s->timer[i].qtimer);
+    }
+}
+
+static void ftpwmtmr010_realize(DeviceState *dev, Error **errp)
+{
+    Ftpwmtmr010State *s = FTPWMTMR010(dev);
+    int i;
+
+    s->step = (uint64_t)get_ticks_per_sec() / (uint64_t)s->freq;
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_FTPWMTMR010,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+    for (i = 0; i < 8; ++i) {
+        s->timer[i].id = i;
+        s->timer[i].chip = s;
+        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
+                                               ftpwmtmr010_timer_tick,
+                                               &s->timer[i]);
+        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->timer[i].irq);
+    }
+}
+
+static const VMStateDescription vmstate_ftpwmtmr010_timer = {
+    .name = TYPE_FTPWMTMR010_TIMER,
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ctrl, Ftpwmtmr010Timer),
+        VMSTATE_UINT32(cntb, Ftpwmtmr010Timer),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_ftpwmtmr010 = {
+    .name = TYPE_FTPWMTMR010,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(stat, Ftpwmtmr010State),
+        VMSTATE_UINT32(freq, Ftpwmtmr010State),
+        VMSTATE_UINT64(step, Ftpwmtmr010State),
+        VMSTATE_STRUCT_ARRAY(timer, Ftpwmtmr010State, 8, 1,
+                        vmstate_ftpwmtmr010_timer, Ftpwmtmr010Timer),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static Property ftpwmtmr010_properties[] = {
+    DEFINE_PROP_UINT32("freq", Ftpwmtmr010State, freq, 66000000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ftpwmtmr010_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd    = &vmstate_ftpwmtmr010;
+    dc->props   = ftpwmtmr010_properties;
+    dc->reset   = ftpwmtmr010_reset;
+    dc->realize = ftpwmtmr010_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftpwmtmr010_info = {
+    .name          = TYPE_FTPWMTMR010,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Ftpwmtmr010State),
+    .class_init    = ftpwmtmr010_class_init,
+};
+
+static void ftpwmtmr010_register_types(void)
+{
+    type_register_static(&ftpwmtmr010_info);
+}
+
+type_init(ftpwmtmr010_register_types)
diff --git a/hw/arm/ftpwmtmr010.h b/hw/arm/ftpwmtmr010.h
new file mode 100644
index 0000000..a435a70
--- /dev/null
+++ b/hw/arm/ftpwmtmr010.h
@@ -0,0 +1,31 @@
+/*
+ * Faraday FTPWMTMR010 Timer.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#ifndef HW_ARM_FTPWMTMR010_H
+#define HW_ARM_FTPWMTMR010_H
+
+#include "qemu/bitops.h"
+
+#define REG_SR              0x00    /* status register */
+#define REG_REVR            0x90    /* revision register */
+
+#define REG_TIMER_BASE(id)  (0x00 + ((id) << 4))
+#define REG_TIMER_CTRL      0x00
+#define REG_TIMER_CNTB      0x04
+#define REG_TIMER_CMPB      0x08
+#define REG_TIMER_CNTO      0x0C
+
+#define TIMER_CTRL_EXTCK        BIT(0)  /* external clock */
+#define TIMER_CTRL_START        BIT(1)
+#define TIMER_CTRL_UPDATE       BIT(2)
+#define TIMER_CTRL_AUTORELOAD   BIT(4)
+#define TIMER_CTRL_INTR         BIT(5)  /* interrupt enabled */
+#define TIMER_CTRL_INTR_EDGE    BIT(6)  /* interrupt type: 1=edge 0=level */
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 07/24] hw/arm: add FTWDT010 watchdog timer support
  2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
                   ` (5 preceding siblings ...)
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 06/24] hw/arm: add FTPWMTMR010 timer support Kuo-Jung Su
@ 2013-03-15 13:13 ` Kuo-Jung Su
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 08/24] hw/arm: add FTRTC011 RTC " Kuo-Jung Su
  7 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Wei-Ren Chen, Blue Swirl, Paul Brook,
	Kuo-Jung Su, Paolo Bonzini, Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The FTWDT010 is used to prevent system from infinite loop
while software gets trapped in the deadlock.

Under the normal operation, users should restart FTWDT010
at the regular intervals before counter counts down to 0.

If the counter does reach 0, FTWDT010 will try to reset
the system by generating one or a combination of signals,
system reset, system interrupt, and external interrupt.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs      |    1 +
 hw/arm/faraday_a369_soc.c |   14 +++
 hw/arm/ftwdt010.c         |  209 +++++++++++++++++++++++++++++++++++++++++++++
 hw/arm/ftwdt010.h         |   35 ++++++++
 4 files changed, 259 insertions(+)
 create mode 100644 hw/arm/ftwdt010.c
 create mode 100644 hw/arm/ftwdt010.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index bc18e22..bd330f2 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -41,3 +41,4 @@ obj-y += ftintc020.o
 obj-y += ftahbc020.o
 obj-y += ftddrii030.o
 obj-y += ftpwmtmr010.o
+obj-y += ftwdt010.o
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index 874dc74..2ec066d 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -68,6 +68,16 @@ static void a369soc_reset(DeviceState *ds)
 }
 
 static void
+a369soc_system_reset(void *opaque)
+{
+    FaradaySoCState *s = FARADAY_SOC(opaque);
+
+    if (s->cpu) {
+        cpu_reset(CPU(s->cpu));
+    }
+}
+
+static void
 a369soc_device_init(FaradaySoCState *s)
 {
     Error *local_errp = NULL;
@@ -177,6 +187,10 @@ a369soc_device_init(FaradaySoCState *s)
     sysbus_connect_irq(SYS_BUS_DEVICE(ds), 1, s->pic[9]);
     sysbus_connect_irq(SYS_BUS_DEVICE(ds), 2, s->pic[10]);
     sysbus_connect_irq(SYS_BUS_DEVICE(ds), 3, s->pic[11]);
+
+    /* ftwdt010 */
+    sysbus_create_simple("ftwdt010", 0x92200000, s->pic[46]);
+    qemu_register_reset(a369soc_system_reset, s);
 }
 
 static void a369soc_realize(DeviceState *dev, Error **errp)
diff --git a/hw/arm/ftwdt010.c b/hw/arm/ftwdt010.c
new file mode 100644
index 0000000..d9613ca
--- /dev/null
+++ b/hw/arm/ftwdt010.c
@@ -0,0 +1,209 @@
+/*
+ * QEMU model of the FTWDT010 WatchDog Timer
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2+.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/watchdog.h"
+#include "sysemu/sysemu.h"
+#include "qemu/timer.h"
+
+#include "ftwdt010.h"
+
+#define TYPE_FTWDT010   "ftwdt010"
+
+typedef struct Ftwdt010State {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+
+    qemu_irq irq;
+
+    QEMUTimer *qtimer;
+
+    uint64_t timeout;
+    uint64_t freq;        /* desired source clock */
+    uint64_t step;        /* get_ticks_per_sec() / freq */
+    bool running;
+
+    /* HW register cache */
+    uint32_t load;
+    uint32_t cr;
+    uint32_t sr;
+} Ftwdt010State;
+
+#define FTWDT010(obj) \
+    OBJECT_CHECK(Ftwdt010State, obj, TYPE_FTWDT010)
+
+static uint64_t
+ftwdt010_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    Ftwdt010State *s = FTWDT010(opaque);
+    uint32_t ret = 0;
+
+    switch (addr) {
+    case REG_COUNTER:
+        if (s->cr & CR_EN) {
+            ret = s->timeout - qemu_get_clock_ms(rt_clock);
+            ret = MIN(s->load, ret * 1000000ULL / s->step);
+        } else {
+            ret = s->load;
+        }
+        break;
+    case REG_LOAD:
+        return s->load;
+    case REG_CR:
+        return s->cr;
+    case REG_SR:
+        return s->sr;
+    case REG_REVR:
+        return 0x00010601;  /* rev. 1.6.1 */
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftwdt010: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+ftwdt010_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    Ftwdt010State *s = FTWDT010(opaque);
+
+    switch (addr) {
+    case REG_LOAD:
+        s->load = (uint32_t)val;
+        break;
+    case REG_RESTART:
+        if ((s->cr & CR_EN) && (val == WDT_MAGIC)) {
+            s->timeout = (s->step * (uint64_t)s->load) / 1000000ULL;
+            s->timeout = qemu_get_clock_ms(rt_clock) + MAX(s->timeout, 1);
+            qemu_mod_timer(s->qtimer, s->timeout);
+        }
+        break;
+    case REG_CR:
+        s->cr = (uint32_t)val;
+        if (s->cr & CR_EN) {
+            if (s->running) {
+                break;
+            }
+            s->running = true;
+            s->timeout = (s->step * (uint64_t)s->load) / 1000000ULL;
+            s->timeout = qemu_get_clock_ms(rt_clock) + MAX(s->timeout, 1);
+            qemu_mod_timer(s->qtimer, s->timeout);
+        } else {
+            s->running = false;
+            qemu_del_timer(s->qtimer);
+        }
+        break;
+    case REG_SCR:
+        s->sr &= ~(uint32_t)val;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftwdt010: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = ftwdt010_mem_read,
+    .write = ftwdt010_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void ftwdt010_timer_tick(void *opaque)
+{
+    Ftwdt010State *s = FTWDT010(opaque);
+
+    s->sr = SR_SRST;
+
+    /* send interrupt signal */
+    qemu_set_irq(s->irq, (s->cr & CR_INTR) ? 1 : 0);
+
+    /* send system reset */
+    if (s->cr & CR_SRST) {
+        watchdog_perform_action();
+    }
+}
+
+static void ftwdt010_reset(DeviceState *ds)
+{
+    Ftwdt010State *s = FTWDT010(SYS_BUS_DEVICE(ds));
+
+    s->cr      = 0;
+    s->sr      = 0;
+    s->load    = 0x3ef1480;
+    s->timeout = 0;
+}
+
+static void ftwdt010_realize(DeviceState *dev, Error **errp)
+{
+    Ftwdt010State *s = FTWDT010(dev);
+
+    s->step = (uint64_t)get_ticks_per_sec() / s->freq;
+    s->qtimer = qemu_new_timer_ms(rt_clock, ftwdt010_timer_tick, s);
+
+    memory_region_init_io(&s->mmio,
+                          &mmio_ops,
+                          s,
+                          TYPE_FTWDT010,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+}
+
+static const VMStateDescription vmstate_ftwdt010 = {
+    .name = TYPE_FTWDT010,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(timeout, Ftwdt010State),
+        VMSTATE_UINT64(freq, Ftwdt010State),
+        VMSTATE_UINT64(step, Ftwdt010State),
+        VMSTATE_UINT32(load, Ftwdt010State),
+        VMSTATE_UINT32(cr, Ftwdt010State),
+        VMSTATE_UINT32(sr, Ftwdt010State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property ftwdt010_properties[] = {
+    DEFINE_PROP_UINT64("freq", Ftwdt010State, freq, 66000000ULL),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ftwdt010_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd    = &vmstate_ftwdt010;
+    dc->props   = ftwdt010_properties;
+    dc->reset   = ftwdt010_reset;
+    dc->realize = ftwdt010_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftwdt010_info = {
+    .name           = TYPE_FTWDT010,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(Ftwdt010State),
+    .class_init     = ftwdt010_class_init,
+};
+
+static void ftwdt010_register_types(void)
+{
+    type_register_static(&ftwdt010_info);
+}
+
+type_init(ftwdt010_register_types)
diff --git a/hw/arm/ftwdt010.h b/hw/arm/ftwdt010.h
new file mode 100644
index 0000000..46c0871
--- /dev/null
+++ b/hw/arm/ftwdt010.h
@@ -0,0 +1,35 @@
+/*
+ * QEMU model of the FTWDT010 WatchDog Timer
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2+.
+ */
+
+#ifndef HW_ARM_FTWDT010_H
+#define HW_ARM_FTWDT010_H
+
+#include "qemu/bitops.h"
+
+/* Hardware registers */
+#define REG_COUNTER     0x00    /* counter register */
+#define REG_LOAD        0x04    /* (re)load register */
+#define REG_RESTART     0x08    /* restart register */
+#define REG_CR          0x0C    /* control register */
+#define REG_SR          0x10    /* status register */
+#define REG_SCR         0x14    /* status clear register */
+#define REG_INTR_LEN    0x18    /* interrupt length register */
+#define REG_REVR        0x1C    /* revision register */
+
+#define CR_CLKS         BIT(4)  /* clock source */
+#define CR_ESIG         BIT(3)  /* external signal enabled */
+#define CR_INTR         BIT(2)  /* system reset interrupt enabled */
+#define CR_SRST         BIT(1)  /* system reset enabled */
+#define CR_EN           BIT(0)  /* chip enabled */
+
+#define SR_SRST         BIT(1)  /* system reset */
+
+#define WDT_MAGIC       0x5ab9  /* magic for watchdog restart */
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 08/24] hw/arm: add FTRTC011 RTC timer support
  2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
                   ` (6 preceding siblings ...)
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 07/24] hw/arm: add FTWDT010 watchdog " Kuo-Jung Su
@ 2013-03-15 13:13 ` Kuo-Jung Su
  7 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Wei-Ren Chen, Blue Swirl, Paul Brook,
	Kuo-Jung Su, Paolo Bonzini, Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

It provides separate second, minute, hour, and day counters. The second
counter is toggled each second, the minute counter is toggled each minute,
the hour counter is toggled each hour, and the day counter is toggled each day.

The FTRTC011 provides a programmable auto-alarm function. When the second
auto-alarm function is turned on, the RTC will automatically trigger an
interrupt each second. The automatic minute and hour alarms can be turned on
as well.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs      |    1 +
 hw/arm/faraday_a369_soc.c |   18 +++
 hw/arm/ftrtc011.c         |  383 +++++++++++++++++++++++++++++++++++++++++++++
 hw/arm/ftrtc011.h         |   53 +++++++
 4 files changed, 455 insertions(+)
 create mode 100644 hw/arm/ftrtc011.c
 create mode 100644 hw/arm/ftrtc011.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index bd330f2..b01da9d 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -42,3 +42,4 @@ obj-y += ftahbc020.o
 obj-y += ftddrii030.o
 obj-y += ftpwmtmr010.o
 obj-y += ftwdt010.o
+obj-y += ftrtc011.o
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index 2ec066d..7d90079 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -191,6 +191,24 @@ a369soc_device_init(FaradaySoCState *s)
     /* ftwdt010 */
     sysbus_create_simple("ftwdt010", 0x92200000, s->pic[46]);
     qemu_register_reset(a369soc_system_reset, s);
+
+    /* ftrtc011 */
+    ds = qdev_create(NULL, "ftrtc011");
+    /* Setup QOM path for QTest */
+    object_property_add_child(OBJECT(s),
+                              "ftrtc011",
+                              OBJECT(ds),
+                              NULL);
+    qdev_init_nofail(ds);
+    sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, 0x92100000);
+    /* Alarm (Edge) */
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 1, s->pic[42]);
+    /* Second (Edge) */
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 2, s->pic[43]);
+    /* Minute (Edge) */
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 3, s->pic[44]);
+    /* Hour (Edge) */
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 4, s->pic[45]);
 }
 
 static void a369soc_realize(DeviceState *dev, Error **errp)
diff --git a/hw/arm/ftrtc011.c b/hw/arm/ftrtc011.c
new file mode 100644
index 0000000..2815f16
--- /dev/null
+++ b/hw/arm/ftrtc011.c
@@ -0,0 +1,383 @@
+/*
+ * QEMU model of the FTRTC011 RTC Timer
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2+.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+#include "ftrtc011.h"
+
+enum ftrtc011_irqpin {
+    IRQ_ALARM_LEVEL = 0,
+    IRQ_ALARM_EDGE,
+    IRQ_SEC,
+    IRQ_MIN,
+    IRQ_HOUR,
+    IRQ_DAY,
+};
+
+#define TYPE_FTRTC011   "ftrtc011"
+
+#define CFG_REGSIZE     (0x3c / 4)
+
+typedef struct Ftrtc011State {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+
+    qemu_irq irq[6];
+
+    QEMUTimer *qtimer;
+    int64_t rtc_base;
+    int64_t rtc_start;
+
+    /* HW register caches */
+    uint32_t regs[CFG_REGSIZE];
+} Ftrtc011State;
+
+#define FTRTC011(obj) \
+    OBJECT_CHECK(Ftrtc011State, obj, TYPE_FTRTC011)
+
+#define RTC_REG32(s, off) \
+    ((s)->regs[(off) / 4])
+
+/* Update interrupts.  */
+static void ftrtc011_update_irq(Ftrtc011State *s)
+{
+    uint32_t mask = extract32(RTC_REG32(s, REG_CR), 1, 5)
+                  & RTC_REG32(s, REG_ISR);
+
+    qemu_set_irq(s->irq[IRQ_ALARM_LEVEL], !!(mask & ISR_ALARM));
+
+    if (mask) {
+        if (mask & ISR_SEC) {
+            qemu_irq_pulse(s->irq[IRQ_SEC]);
+        }
+        if (mask & ISR_MIN) {
+            qemu_irq_pulse(s->irq[IRQ_MIN]);
+        }
+        if (mask & ISR_HOUR) {
+            qemu_irq_pulse(s->irq[IRQ_HOUR]);
+        }
+        if (mask & ISR_DAY) {
+            qemu_irq_pulse(s->irq[IRQ_DAY]);
+        }
+        if (mask & ISR_ALARM) {
+            qemu_irq_pulse(s->irq[IRQ_ALARM_EDGE]);
+        }
+    }
+}
+
+static void ftrtc011_timer_rebase(Ftrtc011State *s)
+{
+    int64_t ticks = get_ticks_per_sec();
+    int64_t elapsed = RTC_REG32(s, REG_SEC)
+                    + (60LL * RTC_REG32(s, REG_MIN))
+                    + (3600LL * RTC_REG32(s, REG_HOUR))
+                    + (86400LL * RTC_REG32(s, REG_DAY));
+
+    s->rtc_base  = elapsed;
+    s->rtc_start = qemu_get_clock_ns(rtc_clock);
+    /* adjust to the beginning of the current second */
+    s->rtc_start = s->rtc_start - (s->rtc_start % ticks);
+}
+
+static void ftrtc011_timer_update(Ftrtc011State *s)
+{
+    int64_t elapsed;
+    uint8_t sec, min, hr;
+    uint32_t day;
+
+    /* check if RTC is enabled */
+    if (!(RTC_REG32(s, REG_CR) & CR_EN)) {
+        return;
+    }
+
+    /*
+     * 2013.03.11 Kuo-Jung Su
+     * Under QTest, in the very beginning of test,
+     * qemu_get_clock_ns(rtc_clock) would somehow jumps
+     * from 0 sec into 436474 sec.
+     * So I have to apply this simple work-aroud to make it work.
+     */
+    if (!s->rtc_start) {
+        ftrtc011_timer_rebase(s);
+    }
+
+    /*
+     * Although the timer is supposed to tick per second,
+     * there is no guarantee that the tick interval is exactly
+     * 1 and only 1 second.
+     */
+    elapsed = s->rtc_base
+            + (qemu_get_clock_ns(rtc_clock) - s->rtc_start) / 1000000000LL;
+    day = (uint32_t)(elapsed / 86400LL);
+    elapsed %= 86400LL;
+    hr = (uint8_t)(elapsed / 3600LL);
+    elapsed %= 3600LL;
+    min = (uint8_t)(elapsed / 60LL);
+    elapsed %= 60LL;
+    sec = elapsed;
+
+    /* sec interrupt */
+    if ((RTC_REG32(s, REG_SEC) != sec)
+        && (RTC_REG32(s, REG_CR) & CR_INTR_SEC)) {
+        RTC_REG32(s, REG_ISR) |= ISR_SEC;
+    }
+    /* min interrupt */
+    if ((RTC_REG32(s, REG_MIN) != min)
+        && (RTC_REG32(s, REG_CR) & CR_INTR_MIN)) {
+        RTC_REG32(s, REG_ISR) |= ISR_MIN;
+    }
+    /* hr interrupt */
+    if ((RTC_REG32(s, REG_HOUR) != hr)
+        && (RTC_REG32(s, REG_CR) & CR_INTR_HOUR)) {
+        RTC_REG32(s, REG_ISR) |= ISR_HOUR;
+    }
+    /* day interrupt */
+    if ((RTC_REG32(s, REG_DAY) != day)
+        && (RTC_REG32(s, REG_CR) & CR_INTR_DAY)) {
+        RTC_REG32(s, REG_ISR) |= ISR_DAY;
+    }
+
+    /* update RTC registers */
+    RTC_REG32(s, REG_SEC) = (uint8_t)sec;
+    RTC_REG32(s, REG_MIN) = (uint8_t)min;
+    RTC_REG32(s, REG_HOUR) = (uint8_t)hr;
+    RTC_REG32(s, REG_DAY) = (uint16_t)day;
+
+    /* alarm interrupt */
+    if (RTC_REG32(s, REG_CR) & CR_INTR_ALARM) {
+        if ((RTC_REG32(s, REG_SEC)
+            | (RTC_REG32(s, REG_MIN) << 8)
+            | (RTC_REG32(s, REG_HOUR) << 16)) ==
+                (RTC_REG32(s, REG_ALARM_SEC)
+                | (RTC_REG32(s, REG_ALARM_MIN) << 8)
+                | (RTC_REG32(s, REG_ALARM_HOUR) << 16))) {
+            RTC_REG32(s, REG_ISR) |= ISR_ALARM;
+        }
+    }
+
+    /* set interrupt signal */
+    ftrtc011_update_irq(s);
+}
+
+static void ftrtc011_timer_resche(Ftrtc011State *s)
+{
+    uint32_t cr = RTC_REG32(s, REG_CR);
+    int64_t  ticks = get_ticks_per_sec();
+    int64_t  timeout = 0;
+
+    if ((cr & CR_EN) && (cr & CR_INTR_MASK)) {
+        timeout = qemu_get_clock_ns(rtc_clock) + ticks;
+    }
+
+    if (timeout > 0) {
+        qemu_mod_timer(s->qtimer, timeout);
+    }
+}
+
+static uint64_t
+ftrtc011_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    Ftrtc011State *s = FTRTC011(opaque);
+    uint32_t ret = 0;
+
+    switch (addr) {
+    case REG_SEC ... REG_DAY:
+        ftrtc011_timer_update(s);
+        /* fall-through */
+    case REG_ALARM_SEC ... REG_ISR:
+        ret = s->regs[addr / 4];
+        break;
+    case REG_REVR:
+        ret = 0x00010000;  /* rev. 1.0.0 */
+        break;
+    case REG_CURRENT:
+        ftrtc011_timer_update(s);
+        ret |= RTC_REG32(s, REG_DAY) << 17;
+        ret |= RTC_REG32(s, REG_HOUR) << 12;
+        ret |= RTC_REG32(s, REG_MIN) << 6;
+        ret |= RTC_REG32(s, REG_SEC);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftrtc011: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+ftrtc011_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    Ftrtc011State *s = FTRTC011(opaque);
+
+    switch (addr) {
+    case REG_ALARM_SEC ... REG_ALARM_HOUR:
+        /* fall-through */
+    case REG_WSEC ... REG_WHOUR:
+        s->regs[addr / 4] = (uint32_t)val & 0xff;
+        break;
+    case REG_WDAY:
+        s->regs[addr / 4] = (uint32_t)val & 0xffff;
+        break;
+    case REG_CR:
+        /* check if RTC is enabled */
+        if (val & CR_EN) {
+            /* update the RTC counter with the user supplied values */
+            if (val & CR_LOAD) {
+                RTC_REG32(s, REG_SEC) = RTC_REG32(s, REG_WSEC);
+                RTC_REG32(s, REG_MIN) = RTC_REG32(s, REG_WMIN);
+                RTC_REG32(s, REG_HOUR) = RTC_REG32(s, REG_WHOUR);
+                RTC_REG32(s, REG_DAY) = RTC_REG32(s, REG_WDAY);
+                val &= ~CR_LOAD;
+                ftrtc011_timer_rebase(s);
+            } else if (!(RTC_REG32(s, REG_CR) & CR_EN)) {
+                ftrtc011_timer_rebase(s);
+            }
+        } else {
+            qemu_del_timer(s->qtimer);
+        }
+        RTC_REG32(s, REG_CR) = (uint32_t)val;
+        /* reschedule a RTC timer update */
+        ftrtc011_timer_resche(s);
+        break;
+    case REG_ISR:
+        RTC_REG32(s, REG_ISR) &= ~((uint32_t)val);
+        ftrtc011_update_irq(s);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftrtc011: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    if (RTC_REG32(s, REG_ALARM_SEC) > 59
+        || RTC_REG32(s, REG_ALARM_MIN) > 59
+        || RTC_REG32(s, REG_ALARM_HOUR) > 23
+        || RTC_REG32(s, REG_WSEC) > 59
+        || RTC_REG32(s, REG_WMIN) > 59
+        || RTC_REG32(s, REG_WHOUR) > 23) {
+        goto werr;
+    }
+
+    return;
+
+werr:
+    qemu_log_mask(LOG_GUEST_ERROR,
+            "ftrtc011: %u is an invalid value to reg@0x%02x.\n",
+            (uint32_t)val, (uint32_t)addr);
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = ftrtc011_mem_read,
+    .write = ftrtc011_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void ftrtc011_timer_tick(void *opaque)
+{
+    Ftrtc011State *s = FTRTC011(opaque);
+    ftrtc011_timer_update(s);
+    ftrtc011_timer_resche(s);
+}
+
+static void ftrtc011_reset(DeviceState *ds)
+{
+    Ftrtc011State *s = FTRTC011(SYS_BUS_DEVICE(ds));
+
+    qemu_del_timer(s->qtimer);
+    memset(s->regs, 0, sizeof(s->regs));
+    ftrtc011_update_irq(s);
+}
+
+static void ftrtc011_save(QEMUFile *f, void *opaque)
+{
+    int i;
+    Ftrtc011State *s = FTRTC011(opaque);
+
+    for (i = 0; i < sizeof(s->regs) / 4; ++i) {
+        qemu_put_be32(f, s->regs[i]);
+    }
+}
+
+static int ftrtc011_load(QEMUFile *f, void *opaque, int version_id)
+{
+    int i;
+    Ftrtc011State *s = FTRTC011(opaque);
+
+    for (i = 0; i < sizeof(s->regs) / 4; ++i) {
+        s->regs[i] = qemu_get_be32(f);
+    }
+
+    return 0;
+}
+
+static void ftrtc011_realize(DeviceState *dev, Error **errp)
+{
+    Ftrtc011State *s = FTRTC011(dev);
+
+    s->qtimer = qemu_new_timer_ns(rtc_clock, ftrtc011_timer_tick, s);
+
+    memory_region_init_io(&s->mmio,
+                          &mmio_ops,
+                          s,
+                          TYPE_FTRTC011,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[IRQ_ALARM_LEVEL]);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[IRQ_ALARM_EDGE]);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[IRQ_SEC]);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[IRQ_MIN]);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[IRQ_HOUR]);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[IRQ_DAY]);
+
+    register_savevm(&s->busdev.qdev, TYPE_FTRTC011, -1, 0,
+                    ftrtc011_save, ftrtc011_load, s);
+}
+
+static const VMStateDescription vmstate_ftrtc011 = {
+    .name = TYPE_FTRTC011,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, Ftrtc011State, CFG_REGSIZE),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ftrtc011_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd    = &vmstate_ftrtc011;
+    dc->reset   = ftrtc011_reset;
+    dc->realize = ftrtc011_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftrtc011_info = {
+    .name           = TYPE_FTRTC011,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(Ftrtc011State),
+    .class_init     = ftrtc011_class_init,
+};
+
+static void ftrtc011_register_types(void)
+{
+    type_register_static(&ftrtc011_info);
+}
+
+type_init(ftrtc011_register_types)
diff --git a/hw/arm/ftrtc011.h b/hw/arm/ftrtc011.h
new file mode 100644
index 0000000..6e23d5e
--- /dev/null
+++ b/hw/arm/ftrtc011.h
@@ -0,0 +1,53 @@
+/*
+ * QEMU model of the FTRTC011 RTC Timer
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2+.
+ */
+#ifndef HW_ARM_FTRTC011_H
+#define HW_ARM_FTRTC011_H
+
+#include "qemu/bitops.h"
+
+/* Hardware registers */
+#define REG_SEC         0x00
+#define REG_MIN         0x04
+#define REG_HOUR        0x08
+#define REG_DAY         0x0C
+
+#define REG_ALARM_SEC   0x10    /* Alarm: sec */
+#define REG_ALARM_MIN   0x14    /* Alarm: min */
+#define REG_ALARM_HOUR  0x18    /* Alarm: hour */
+
+#define REG_CR          0x20    /* Control Register */
+#define REG_WSEC        0x24    /* Write SEC Register */
+#define REG_WMIN        0x28    /* Write MIN Register */
+#define REG_WHOUR       0x2C    /* Write HOUR Register */
+#define REG_WDAY        0x30    /* Write DAY Register */
+#define REG_ISR         0x34    /* Interrupt Status Register */
+
+#define REG_REVR        0x3C    /* Revision Register */
+#define REG_CURRENT     0x44    /* Group-up day/hour/min/sec as a register */
+
+#define CR_LOAD         BIT(6)  /* Update counters by Wxxx registers */
+#define CR_INTR_ALARM   BIT(5)  /* Alarm interrupt enabled */
+#define CR_INTR_DAY     BIT(4)  /* DDAY interrupt enabled */
+#define CR_INTR_HOUR    BIT(3)  /* HOUR interrupt enabled */
+#define CR_INTR_MIN     BIT(2)  /* MIN interrupt enabled */
+#define CR_INTR_SEC     BIT(1)  /* SEC interrupt enabled */
+#define CR_INTR_MASK    (CR_INTR_SEC | CR_INTR_MIN \
+                        | CR_INTR_HOUR | CR_INTR_DAY | CR_INTR_ALARM)
+#define CR_EN           BIT(0)  /* RTC enabled */
+
+#define ISR_LOAD        BIT(5)  /* CR_LOAD finished (no interrupt occurs) */
+#define ISR_ALARM       BIT(4)
+#define ISR_DAY         BIT(3)
+#define ISR_HOUR        BIT(2)
+#define ISR_MIN         BIT(1)
+#define ISR_SEC         BIT(0)
+#define ISR_MASK        (ISR_SEC | ISR_MIN \
+                        | ISR_HOUR | ISR_DAY | ISR_ALARM | ISR_LOAD)
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v8 06/24] hw/arm: add FTPWMTMR010 timer support
  2013-03-15 13:15 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
@ 2013-03-15 13:15 ` Kuo-Jung Su
  0 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-15 13:15 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, i.mitsyanko, Blue Swirl, Paul Brook, Kuo-Jung Su,
	Andreas, fred.konrad

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The FTPWMTMR010 is an APB device which provides up to 8 independent timers.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs      |    1 +
 hw/arm/faraday_a369_soc.c |   10 ++
 hw/arm/ftpwmtmr010.c      |  258 +++++++++++++++++++++++++++++++++++++++++++++
 hw/arm/ftpwmtmr010.h      |   31 ++++++
 4 files changed, 300 insertions(+)
 create mode 100644 hw/arm/ftpwmtmr010.c
 create mode 100644 hw/arm/ftpwmtmr010.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 0bbf838..bc18e22 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -40,3 +40,4 @@ obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
 obj-y += ftintc020.o
 obj-y += ftahbc020.o
 obj-y += ftddrii030.o
+obj-y += ftpwmtmr010.o
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index e8a63bb..874dc74 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -167,6 +167,16 @@ a369soc_device_init(FaradaySoCState *s)
         fprintf(stderr, "a369soc: Unable to set soc link for FTDDRII030\n");
         abort();
     }
+
+    /* Timer */
+    ds = qdev_create(NULL, "ftpwmtmr010");
+    qdev_prop_set_uint32(ds, "freq", 66 * 1000000);
+    qdev_init_nofail(ds);
+    sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, 0x92300000);
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 0, s->pic[8]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 1, s->pic[9]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 2, s->pic[10]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(ds), 3, s->pic[11]);
 }
 
 static void a369soc_realize(DeviceState *dev, Error **errp)
diff --git a/hw/arm/ftpwmtmr010.c b/hw/arm/ftpwmtmr010.c
new file mode 100644
index 0000000..c212cfe
--- /dev/null
+++ b/hw/arm/ftpwmtmr010.c
@@ -0,0 +1,258 @@
+/*
+ * Faraday FTPWMTMR010 Timer.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+#include "ftpwmtmr010.h"
+
+#define TYPE_FTPWMTMR010        "ftpwmtmr010"
+#define TYPE_FTPWMTMR010_TIMER  "ftpwmtmr010_timer"
+
+typedef struct Ftpwmtmr010State Ftpwmtmr010State;
+
+typedef struct Ftpwmtmr010Timer {
+    uint32_t ctrl;
+    uint32_t cntb;
+    int id;
+    uint64_t timeout;
+    uint64_t countdown;
+    qemu_irq irq;
+    QEMUTimer *qtimer;
+    Ftpwmtmr010State *chip;
+} Ftpwmtmr010Timer;
+
+struct Ftpwmtmr010State {
+    SysBusDevice busdev;
+
+    MemoryRegion iomem;
+    Ftpwmtmr010Timer timer[8];
+    uint32_t freq;        /* desired source clock */
+    uint64_t step;        /* get_ticks_per_sec() / freq */
+    uint32_t stat;
+};
+
+#define FTPWMTMR010(obj) \
+    OBJECT_CHECK(Ftpwmtmr010State, obj, TYPE_FTPWMTMR010)
+
+static uint64_t
+ftpwmtmr010_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    Ftpwmtmr010State *s = FTPWMTMR010(opaque);
+    Ftpwmtmr010Timer *t;
+    uint64_t now = qemu_get_clock_ns(vm_clock);
+    uint64_t ret = 0;
+
+    switch (addr) {
+    case REG_SR:
+        ret = s->stat;
+        break;
+    case REG_REVR:
+        ret = 0x00000000;   /* Rev. 0.0.0 (no rev. id) */
+        break;
+    case REG_TIMER_BASE(1) ... REG_TIMER_BASE(8) + 0x0C:
+        t = s->timer + (addr >> 4) - 1;
+        switch (addr & 0x0f) {
+        case REG_TIMER_CTRL:
+            return t->ctrl;
+        case REG_TIMER_CNTB:
+            return t->cntb;
+        case REG_TIMER_CNTO:
+            if ((t->ctrl & TIMER_CTRL_START) && (t->timeout > now)) {
+                ret = (t->timeout - now) / s->step;
+            }
+            break;
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftpwmtmr010: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+ftpwmtmr010_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    Ftpwmtmr010State *s = FTPWMTMR010(opaque);
+    Ftpwmtmr010Timer *t;
+    int i;
+
+    switch (addr) {
+    case REG_SR:
+        s->stat &= ~((uint32_t)val);
+        for (i = 0; i < 8; ++i) {
+            if (val & BIT(i)) {
+                qemu_irq_lower(s->timer[i].irq);
+            }
+        }
+        break;
+    case REG_TIMER_BASE(1) ... REG_TIMER_BASE(8) + 0x0C:
+        t = s->timer + (addr >> 4) - 1;
+        switch (addr & 0x0f) {
+        case REG_TIMER_CTRL:
+            t->ctrl = (uint32_t)val;
+            if (t->ctrl & TIMER_CTRL_UPDATE) {
+                t->countdown = (uint64_t)t->cntb * s->step;
+            }
+            if (t->ctrl & TIMER_CTRL_START) {
+                t->timeout = t->countdown + qemu_get_clock_ns(vm_clock);
+                qemu_mod_timer(t->qtimer, t->timeout);
+            }
+            break;
+        case REG_TIMER_CNTB:
+            t->cntb = (uint32_t)val;
+            break;
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "ftpwmtmr010: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = ftpwmtmr010_mem_read,
+    .write = ftpwmtmr010_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void ftpwmtmr010_timer_tick(void *opaque)
+{
+    Ftpwmtmr010Timer *t = opaque;
+    Ftpwmtmr010State *s = t->chip;
+
+    /* if the timer has been enabled/started */
+    if (!(t->ctrl & TIMER_CTRL_START)) {
+        return;
+    }
+
+    /* if the interrupt enabled */
+    if (t->ctrl & TIMER_CTRL_INTR) {
+        s->stat |= BIT(t->id);
+        if (t->ctrl & TIMER_CTRL_INTR_EDGE) {
+            qemu_irq_pulse(t->irq);
+        } else {
+            qemu_irq_raise(t->irq);
+        }
+    }
+
+    /* if auto-reload is enabled */
+    if (t->ctrl & TIMER_CTRL_AUTORELOAD) {
+        t->timeout = t->countdown + qemu_get_clock_ns(vm_clock);
+        qemu_mod_timer(t->qtimer, t->timeout);
+    } else {
+        t->ctrl &= ~TIMER_CTRL_START;
+    }
+}
+
+static void ftpwmtmr010_reset(DeviceState *ds)
+{
+    Ftpwmtmr010State *s = FTPWMTMR010(SYS_BUS_DEVICE(ds));
+    int i;
+
+    s->stat = 0;
+
+    for (i = 0; i < 8; ++i) {
+        s->timer[i].ctrl = 0;
+        s->timer[i].cntb = 0;
+        s->timer[i].timeout = 0;
+        qemu_irq_lower(s->timer[i].irq);
+        qemu_del_timer(s->timer[i].qtimer);
+    }
+}
+
+static void ftpwmtmr010_realize(DeviceState *dev, Error **errp)
+{
+    Ftpwmtmr010State *s = FTPWMTMR010(dev);
+    int i;
+
+    s->step = (uint64_t)get_ticks_per_sec() / (uint64_t)s->freq;
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_FTPWMTMR010,
+                          0x1000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+    for (i = 0; i < 8; ++i) {
+        s->timer[i].id = i;
+        s->timer[i].chip = s;
+        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
+                                               ftpwmtmr010_timer_tick,
+                                               &s->timer[i]);
+        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->timer[i].irq);
+    }
+}
+
+static const VMStateDescription vmstate_ftpwmtmr010_timer = {
+    .name = TYPE_FTPWMTMR010_TIMER,
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ctrl, Ftpwmtmr010Timer),
+        VMSTATE_UINT32(cntb, Ftpwmtmr010Timer),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_ftpwmtmr010 = {
+    .name = TYPE_FTPWMTMR010,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(stat, Ftpwmtmr010State),
+        VMSTATE_UINT32(freq, Ftpwmtmr010State),
+        VMSTATE_UINT64(step, Ftpwmtmr010State),
+        VMSTATE_STRUCT_ARRAY(timer, Ftpwmtmr010State, 8, 1,
+                        vmstate_ftpwmtmr010_timer, Ftpwmtmr010Timer),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static Property ftpwmtmr010_properties[] = {
+    DEFINE_PROP_UINT32("freq", Ftpwmtmr010State, freq, 66000000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ftpwmtmr010_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd    = &vmstate_ftpwmtmr010;
+    dc->props   = ftpwmtmr010_properties;
+    dc->reset   = ftpwmtmr010_reset;
+    dc->realize = ftpwmtmr010_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftpwmtmr010_info = {
+    .name          = TYPE_FTPWMTMR010,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Ftpwmtmr010State),
+    .class_init    = ftpwmtmr010_class_init,
+};
+
+static void ftpwmtmr010_register_types(void)
+{
+    type_register_static(&ftpwmtmr010_info);
+}
+
+type_init(ftpwmtmr010_register_types)
diff --git a/hw/arm/ftpwmtmr010.h b/hw/arm/ftpwmtmr010.h
new file mode 100644
index 0000000..a435a70
--- /dev/null
+++ b/hw/arm/ftpwmtmr010.h
@@ -0,0 +1,31 @@
+/*
+ * Faraday FTPWMTMR010 Timer.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#ifndef HW_ARM_FTPWMTMR010_H
+#define HW_ARM_FTPWMTMR010_H
+
+#include "qemu/bitops.h"
+
+#define REG_SR              0x00    /* status register */
+#define REG_REVR            0x90    /* revision register */
+
+#define REG_TIMER_BASE(id)  (0x00 + ((id) << 4))
+#define REG_TIMER_CTRL      0x00
+#define REG_TIMER_CNTB      0x04
+#define REG_TIMER_CMPB      0x08
+#define REG_TIMER_CNTO      0x0C
+
+#define TIMER_CTRL_EXTCK        BIT(0)  /* external clock */
+#define TIMER_CTRL_START        BIT(1)
+#define TIMER_CTRL_UPDATE       BIT(2)
+#define TIMER_CTRL_AUTORELOAD   BIT(4)
+#define TIMER_CTRL_INTR         BIT(5)  /* interrupt enabled */
+#define TIMER_CTRL_INTR_EDGE    BIT(6)  /* interrupt type: 1=edge 0=level */
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support
  2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII " Kuo-Jung Su
@ 2013-03-16  3:32   ` Peter Crosthwaite
  2013-03-18  1:12     ` Kuo-Jung Su
  0 siblings, 1 reply; 16+ messages in thread
From: Peter Crosthwaite @ 2013-03-16  3:32 UTC (permalink / raw)
  To: Kuo-Jung Su
  Cc: Peter Maydell, i.mitsyanko, qemu-devel, Blue Swirl, Paul Brook,
	Kuo-Jung Su, Andreas, fred.konrad

Hi Kuo-Jung,

On Fri, Mar 15, 2013 at 11:13 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> The FTDDRII030 is a DDRII SDRAM controller which is responsible for
> SDRAM initialization.
> In QEMU we emulate only the SDRAM enable function.
>
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> ---
>  hw/arm/Makefile.objs      |    1 +
>  hw/arm/faraday_a369_soc.c |    9 +++
>  hw/arm/ftddrii030.c       |  183 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 193 insertions(+)
>  create mode 100644 hw/arm/ftddrii030.c
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index af36b01..0bbf838 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -39,3 +39,4 @@ obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
>              faraday_a369_kpd.o
>  obj-y += ftintc020.o
>  obj-y += ftahbc020.o
> +obj-y += ftddrii030.o
> diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
> index 01b4395..e8a63bb 100644
> --- a/hw/arm/faraday_a369_soc.c
> +++ b/hw/arm/faraday_a369_soc.c
> @@ -158,6 +158,15 @@ a369soc_device_init(FaradaySoCState *s)
>          fprintf(stderr, "a369soc: Unable to set soc link for FTAHBC020\n");
>          abort();
>      }
> +
> +    /* ftddrii030 */
> +    ds = sysbus_create_simple("ftddrii030", 0x93100000, NULL);
> +    s->ddrc = ds;
> +    object_property_set_link(OBJECT(ds), OBJECT(s), "soc", &local_errp);
> +    if (local_errp) {
> +        fprintf(stderr, "a369soc: Unable to set soc link for FTDDRII030\n");
> +        abort();
> +    }
>  }
>
>  static void a369soc_realize(DeviceState *dev, Error **errp)
> diff --git a/hw/arm/ftddrii030.c b/hw/arm/ftddrii030.c
> new file mode 100644
> index 0000000..90a5842
> --- /dev/null
> +++ b/hw/arm/ftddrii030.c
> @@ -0,0 +1,183 @@
> +/*
> + * Faraday DDRII controller
> + *
> + * Copyright (c) 2012 Faraday Technology
> + * Written by Dante Su <dantesu@faraday-tech.com>
> + *
> + * This code is licensed under GNU GPL v2+
> + */
> +
> +#include "hw/hw.h"
> +#include "hw/sysbus.h"
> +#include "hw/devices.h"
> +#include "sysemu/sysemu.h"
> +
> +#include "faraday.h"
> +
> +#define REG_MCR             0x00    /* memory configuration register */
> +#define REG_MSR             0x04    /* memory status register */
> +#define REG_REVR            0x50    /* revision register */
> +
> +#define MSR_INIT_OK         BIT(8)  /* DDR2 initial is completed */
> +#define MSR_CMD_MRS         BIT(0)  /* start MRS command */
> +
> +#define CFG_REGSIZE         (0x50 / 4)
> +
> +#define TYPE_FTDDRII030     "ftddrii030"
> +
> +typedef struct Ftddrii030State {
> +    SysBusDevice busdev;
> +    MemoryRegion iomem;
> +
> +    FaradaySoCState *soc;
> +    /* HW register cache */
> +    uint32_t regs[CFG_REGSIZE];
> +} Ftddrii030State;
> +
> +#define FTDDRII030(obj) \
> +    OBJECT_CHECK(Ftddrii030State, obj, TYPE_FTDDRII030)
> +
> +#define DDR_REG32(s, off) \
> +    ((s)->regs[(off) / 4])
> +
> +static uint64_t
> +ftddrii030_mem_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    Ftddrii030State *s = FTDDRII030(opaque);
> +    uint64_t ret = 0;
> +
> +    if (s->soc->ddr_inited) {
> +        DDR_REG32(s, REG_MSR) |= MSR_INIT_OK;
> +    }
> +
> +    switch (addr) {
> +    case REG_MCR ... (CFG_REGSIZE - 1) * 4:
> +        ret = s->regs[addr / 4];
> +        break;
> +    case REG_REVR:
> +        ret = 0x100;    /* rev. = 0.1.0 */
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +            "ftddrii030: undefined memory access@%#" HWADDR_PRIx "\n", addr);
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void
> +ftddrii030_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> +{
> +    Ftddrii030State *s = FTDDRII030(opaque);
> +
> +    switch (addr) {
> +    case REG_MCR:
> +        DDR_REG32(s, REG_MCR) = (uint32_t)val & 0xffff;
> +        break;
> +    case REG_MSR:
> +        val = (val & 0x3f) | (DDR_REG32(s, REG_MSR) & MSR_INIT_OK);
> +        if (!s->soc->ddr_inited && (val & MSR_CMD_MRS)) {
> +            val &= ~MSR_CMD_MRS;
> +            val |= MSR_INIT_OK;
> +            memory_region_add_subregion(s->soc->as,
> +                                        s->soc->ram_base,
> +                                        s->soc->ram);

I feel like this is overstepping the bounds of the device. Its
modifying the internals of the parent device (the SoC itself). AFAICT,
this device does not need awareness of where the RAM is to live in the
address map, thats the responsibility of the machine model. It might
be cleaner to model the actual RAM as a second sysbus memory region
then leave it up the machine model to decide where in the address map
it should live. This device just adds/removes the ram from the second
region without knowing where it lives and the machine model maps the
RAM to its actual location. Keeps .as .ram_base and .ram private to
the SoC device.

> +            s->soc->ddr_inited = true;

I'm still trying to figure out the physical analogue of this. Is there
a genuine hardware linkage from the DDR controller to other devices
that says "hey i'm inited" or is this faking firmware activity? In the
former case, this ddr_inited should be a GPIO from DDR controller to
whatever devices care. In the latter case, its trickier, and we should
discuss bootloader based solutions to get your tiny little bit of
firmware in, without having to model non-existent hardware.

Regards,
Peter

> +        }
> +        DDR_REG32(s, REG_MSR) = (uint32_t)val;
> +        break;
> +    case 0x08 ... (CFG_REGSIZE - 1) * 4: /* DDRII Timing, ECC ...etc. */
> +        s->regs[addr / 4] = (uint32_t)val;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +            "ftddrii030: undefined memory access@%#" HWADDR_PRIx "\n", addr);
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps mmio_ops = {
> +    .read  = ftddrii030_mem_read,
> +    .write = ftddrii030_mem_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    }
> +};
> +
> +static void ftddrii030_reset(DeviceState *ds)
> +{
> +    Ftddrii030State *s = FTDDRII030(SYS_BUS_DEVICE(ds));
> +    Error *local_errp = NULL;
> +
> +    s->soc = FARADAY_SOC(object_property_get_link(OBJECT(s),
> +                                                  "soc",
> +                                                  &local_errp));
> +    if (local_errp) {
> +        fprintf(stderr, "ftahbc020: Unable to get soc link\n");
> +        abort();
> +    }
> +
> +    if (s->soc->ddr_inited && !s->soc->bi) {
> +        memory_region_del_subregion(s->soc->as, s->soc->ram);
> +        s->soc->ddr_inited = false;
> +    }
> +
> +    memset(s->regs, 0, sizeof(s->regs));
> +}
> +
> +static void ftddrii030_realize(DeviceState *dev, Error **errp)
> +{
> +    Ftddrii030State *s = FTDDRII030(dev);
> +
> +    memory_region_init_io(&s->iomem,
> +                          &mmio_ops,
> +                          s,
> +                          TYPE_FTDDRII030,
> +                          0x1000);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
> +
> +    object_property_add_link(OBJECT(dev),
> +                             "soc",
> +                             TYPE_FARADAY_SOC,
> +                             (Object **) &s->soc,
> +                             errp);
> +}
> +
> +static const VMStateDescription vmstate_ftddrii030 = {
> +    .name = TYPE_FTDDRII030,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32_ARRAY(regs, Ftddrii030State, CFG_REGSIZE),
> +        VMSTATE_END_OF_LIST(),
> +    }
> +};
> +
> +static void ftddrii030_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->desc  = TYPE_FTDDRII030;
> +    dc->vmsd  = &vmstate_ftddrii030;
> +    dc->reset = ftddrii030_reset;
> +    dc->realize = ftddrii030_realize;
> +    dc->no_user = 1;
> +}
> +
> +static const TypeInfo ftddrii030_info = {
> +    .name          = TYPE_FTDDRII030,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(Ftddrii030State),
> +    .class_init    = ftddrii030_class_init,
> +};
> +
> +static void ftddrii030_register_types(void)
> +{
> +    type_register_static(&ftddrii030_info);
> +}
> +
> +type_init(ftddrii030_register_types)
> --
> 1.7.9.5
>
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support
  2013-03-16  3:32   ` Peter Crosthwaite
@ 2013-03-18  1:12     ` Kuo-Jung Su
  2013-03-18  1:32       ` Peter Crosthwaite
  0 siblings, 1 reply; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-18  1:12 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Igor Mitsyanko, qemu-devel, Blue Swirl, Paul Brook,
	Kuo-Jung Su, Andreas, fred konrad

2013/3/16 Peter Crosthwaite <peter.crosthwaite@xilinx.com>:
> Hi Kuo-Jung,
>
> On Fri, Mar 15, 2013 at 11:13 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> The FTDDRII030 is a DDRII SDRAM controller which is responsible for
>> SDRAM initialization.
>> In QEMU we emulate only the SDRAM enable function.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> ---
>>  hw/arm/Makefile.objs      |    1 +
>>  hw/arm/faraday_a369_soc.c |    9 +++
>>  hw/arm/ftddrii030.c       |  183 +++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 193 insertions(+)
>>  create mode 100644 hw/arm/ftddrii030.c
>>
>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>> index af36b01..0bbf838 100644
>> --- a/hw/arm/Makefile.objs
>> +++ b/hw/arm/Makefile.objs
>> @@ -39,3 +39,4 @@ obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
>>              faraday_a369_kpd.o
>>  obj-y += ftintc020.o
>>  obj-y += ftahbc020.o
>> +obj-y += ftddrii030.o
>> diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
>> index 01b4395..e8a63bb 100644
>> --- a/hw/arm/faraday_a369_soc.c
>> +++ b/hw/arm/faraday_a369_soc.c
>> @@ -158,6 +158,15 @@ a369soc_device_init(FaradaySoCState *s)
>>          fprintf(stderr, "a369soc: Unable to set soc link for FTAHBC020\n");
>>          abort();
>>      }
>> +
>> +    /* ftddrii030 */
>> +    ds = sysbus_create_simple("ftddrii030", 0x93100000, NULL);
>> +    s->ddrc = ds;
>> +    object_property_set_link(OBJECT(ds), OBJECT(s), "soc", &local_errp);
>> +    if (local_errp) {
>> +        fprintf(stderr, "a369soc: Unable to set soc link for FTDDRII030\n");
>> +        abort();
>> +    }
>>  }
>>
>>  static void a369soc_realize(DeviceState *dev, Error **errp)
>> diff --git a/hw/arm/ftddrii030.c b/hw/arm/ftddrii030.c
>> new file mode 100644
>> index 0000000..90a5842
>> --- /dev/null
>> +++ b/hw/arm/ftddrii030.c
>> @@ -0,0 +1,183 @@
>> +/*
>> + * Faraday DDRII controller
>> + *
>> + * Copyright (c) 2012 Faraday Technology
>> + * Written by Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This code is licensed under GNU GPL v2+
>> + */
>> +
>> +#include "hw/hw.h"
>> +#include "hw/sysbus.h"
>> +#include "hw/devices.h"
>> +#include "sysemu/sysemu.h"
>> +
>> +#include "faraday.h"
>> +
>> +#define REG_MCR             0x00    /* memory configuration register */
>> +#define REG_MSR             0x04    /* memory status register */
>> +#define REG_REVR            0x50    /* revision register */
>> +
>> +#define MSR_INIT_OK         BIT(8)  /* DDR2 initial is completed */
>> +#define MSR_CMD_MRS         BIT(0)  /* start MRS command */
>> +
>> +#define CFG_REGSIZE         (0x50 / 4)
>> +
>> +#define TYPE_FTDDRII030     "ftddrii030"
>> +
>> +typedef struct Ftddrii030State {
>> +    SysBusDevice busdev;
>> +    MemoryRegion iomem;
>> +
>> +    FaradaySoCState *soc;
>> +    /* HW register cache */
>> +    uint32_t regs[CFG_REGSIZE];
>> +} Ftddrii030State;
>> +
>> +#define FTDDRII030(obj) \
>> +    OBJECT_CHECK(Ftddrii030State, obj, TYPE_FTDDRII030)
>> +
>> +#define DDR_REG32(s, off) \
>> +    ((s)->regs[(off) / 4])
>> +
>> +static uint64_t
>> +ftddrii030_mem_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> +    Ftddrii030State *s = FTDDRII030(opaque);
>> +    uint64_t ret = 0;
>> +
>> +    if (s->soc->ddr_inited) {
>> +        DDR_REG32(s, REG_MSR) |= MSR_INIT_OK;
>> +    }
>> +
>> +    switch (addr) {
>> +    case REG_MCR ... (CFG_REGSIZE - 1) * 4:
>> +        ret = s->regs[addr / 4];
>> +        break;
>> +    case REG_REVR:
>> +        ret = 0x100;    /* rev. = 0.1.0 */
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +            "ftddrii030: undefined memory access@%#" HWADDR_PRIx "\n", addr);
>> +        break;
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +static void
>> +ftddrii030_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>> +{
>> +    Ftddrii030State *s = FTDDRII030(opaque);
>> +
>> +    switch (addr) {
>> +    case REG_MCR:
>> +        DDR_REG32(s, REG_MCR) = (uint32_t)val & 0xffff;
>> +        break;
>> +    case REG_MSR:
>> +        val = (val & 0x3f) | (DDR_REG32(s, REG_MSR) & MSR_INIT_OK);
>> +        if (!s->soc->ddr_inited && (val & MSR_CMD_MRS)) {
>> +            val &= ~MSR_CMD_MRS;
>> +            val |= MSR_INIT_OK;
>> +            memory_region_add_subregion(s->soc->as,
>> +                                        s->soc->ram_base,
>> +                                        s->soc->ram);
>
> I feel like this is overstepping the bounds of the device. Its
> modifying the internals of the parent device (the SoC itself). AFAICT,
> this device does not need awareness of where the RAM is to live in the
> address map, thats the responsibility of the machine model. It might
> be cleaner to model the actual RAM as a second sysbus memory region
> then leave it up the machine model to decide where in the address map
> it should live. This device just adds/removes the ram from the second
> region without knowing where it lives and the machine model maps the
> RAM to its actual location. Keeps .as .ram_base and .ram private to
> the SoC device.
>

Thanks for the comments,
I'll try to implement a cleaner model in the way suggested in the
above comments.

>> +            s->soc->ddr_inited = true;
>
> I'm still trying to figure out the physical analogue of this. Is there
> a genuine hardware linkage from the DDR controller to other devices
> that says "hey i'm inited" or is this faking firmware activity? In the
> former case, this ddr_inited should be a GPIO from DDR controller to
> whatever devices care. In the latter case, its trickier, and we should
> discuss bootloader based solutions to get your tiny little bit of
> firmware in, without having to model non-existent hardware.
>

Thanks for the comments.
It's the 1st one, it's used to inform the FTAHBC020 of the presence of
DRAM in QEMU model. And thus it could be replaced by a GPIO
implementation.
However in this way, it would slightly disobey the real hardware design.
I'll see if I could find a better way or not. If no luck, I'll try the
GPIO way as you suggested.

Kuo-Jung

> Regards,
> Peter
>
>> +        }
>> +        DDR_REG32(s, REG_MSR) = (uint32_t)val;
>> +        break;
>> +    case 0x08 ... (CFG_REGSIZE - 1) * 4: /* DDRII Timing, ECC ...etc. */
>> +        s->regs[addr / 4] = (uint32_t)val;
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +            "ftddrii030: undefined memory access@%#" HWADDR_PRIx "\n", addr);
>> +        break;
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps mmio_ops = {
>> +    .read  = ftddrii030_mem_read,
>> +    .write = ftddrii030_mem_write,
>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 4,
>> +        .max_access_size = 4,
>> +    }
>> +};
>> +
>> +static void ftddrii030_reset(DeviceState *ds)
>> +{
>> +    Ftddrii030State *s = FTDDRII030(SYS_BUS_DEVICE(ds));
>> +    Error *local_errp = NULL;
>> +
>> +    s->soc = FARADAY_SOC(object_property_get_link(OBJECT(s),
>> +                                                  "soc",
>> +                                                  &local_errp));
>> +    if (local_errp) {
>> +        fprintf(stderr, "ftahbc020: Unable to get soc link\n");
>> +        abort();
>> +    }
>> +
>> +    if (s->soc->ddr_inited && !s->soc->bi) {
>> +        memory_region_del_subregion(s->soc->as, s->soc->ram);
>> +        s->soc->ddr_inited = false;
>> +    }
>> +
>> +    memset(s->regs, 0, sizeof(s->regs));
>> +}
>> +
>> +static void ftddrii030_realize(DeviceState *dev, Error **errp)
>> +{
>> +    Ftddrii030State *s = FTDDRII030(dev);
>> +
>> +    memory_region_init_io(&s->iomem,
>> +                          &mmio_ops,
>> +                          s,
>> +                          TYPE_FTDDRII030,
>> +                          0x1000);
>> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
>> +
>> +    object_property_add_link(OBJECT(dev),
>> +                             "soc",
>> +                             TYPE_FARADAY_SOC,
>> +                             (Object **) &s->soc,
>> +                             errp);
>> +}
>> +
>> +static const VMStateDescription vmstate_ftddrii030 = {
>> +    .name = TYPE_FTDDRII030,
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .minimum_version_id_old = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT32_ARRAY(regs, Ftddrii030State, CFG_REGSIZE),
>> +        VMSTATE_END_OF_LIST(),
>> +    }
>> +};
>> +
>> +static void ftddrii030_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->desc  = TYPE_FTDDRII030;
>> +    dc->vmsd  = &vmstate_ftddrii030;
>> +    dc->reset = ftddrii030_reset;
>> +    dc->realize = ftddrii030_realize;
>> +    dc->no_user = 1;
>> +}
>> +
>> +static const TypeInfo ftddrii030_info = {
>> +    .name          = TYPE_FTDDRII030,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(Ftddrii030State),
>> +    .class_init    = ftddrii030_class_init,
>> +};
>> +
>> +static void ftddrii030_register_types(void)
>> +{
>> +    type_register_static(&ftddrii030_info);
>> +}
>> +
>> +type_init(ftddrii030_register_types)
>> --
>> 1.7.9.5
>>
>>



--
Best wishes,
Kuo-Jung Su

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support
  2013-03-18  1:12     ` Kuo-Jung Su
@ 2013-03-18  1:32       ` Peter Crosthwaite
  2013-03-18  9:56         ` Kuo-Jung Su
  0 siblings, 1 reply; 16+ messages in thread
From: Peter Crosthwaite @ 2013-03-18  1:32 UTC (permalink / raw)
  To: Kuo-Jung Su
  Cc: Peter Maydell, Igor Mitsyanko, qemu-devel, Blue Swirl, Paul Brook,
	Kuo-Jung Su, Andreas, fred konrad

On Mon, Mar 18, 2013 at 11:12 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:
> 2013/3/16 Peter Crosthwaite <peter.crosthwaite@xilinx.com>:
>> Hi Kuo-Jung,
>>
>> On Fri, Mar 15, 2013 at 11:13 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>
>>> The FTDDRII030 is a DDRII SDRAM controller which is responsible for
>>> SDRAM initialization.
>>> In QEMU we emulate only the SDRAM enable function.
>>>
>>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>>> ---
>>>  hw/arm/Makefile.objs      |    1 +
>>>  hw/arm/faraday_a369_soc.c |    9 +++
>>>  hw/arm/ftddrii030.c       |  183 +++++++++++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 193 insertions(+)
>>>  create mode 100644 hw/arm/ftddrii030.c
>>>
>>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>>> index af36b01..0bbf838 100644
>>> --- a/hw/arm/Makefile.objs
>>> +++ b/hw/arm/Makefile.objs
>>> @@ -39,3 +39,4 @@ obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
>>>              faraday_a369_kpd.o
>>>  obj-y += ftintc020.o
>>>  obj-y += ftahbc020.o
>>> +obj-y += ftddrii030.o
>>> diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
>>> index 01b4395..e8a63bb 100644
>>> --- a/hw/arm/faraday_a369_soc.c
>>> +++ b/hw/arm/faraday_a369_soc.c
>>> @@ -158,6 +158,15 @@ a369soc_device_init(FaradaySoCState *s)
>>>          fprintf(stderr, "a369soc: Unable to set soc link for FTAHBC020\n");
>>>          abort();
>>>      }
>>> +
>>> +    /* ftddrii030 */
>>> +    ds = sysbus_create_simple("ftddrii030", 0x93100000, NULL);
>>> +    s->ddrc = ds;
>>> +    object_property_set_link(OBJECT(ds), OBJECT(s), "soc", &local_errp);
>>> +    if (local_errp) {
>>> +        fprintf(stderr, "a369soc: Unable to set soc link for FTDDRII030\n");
>>> +        abort();
>>> +    }
>>>  }
>>>
>>>  static void a369soc_realize(DeviceState *dev, Error **errp)
>>> diff --git a/hw/arm/ftddrii030.c b/hw/arm/ftddrii030.c
>>> new file mode 100644
>>> index 0000000..90a5842
>>> --- /dev/null
>>> +++ b/hw/arm/ftddrii030.c
>>> @@ -0,0 +1,183 @@
>>> +/*
>>> + * Faraday DDRII controller
>>> + *
>>> + * Copyright (c) 2012 Faraday Technology
>>> + * Written by Dante Su <dantesu@faraday-tech.com>
>>> + *
>>> + * This code is licensed under GNU GPL v2+
>>> + */
>>> +
>>> +#include "hw/hw.h"
>>> +#include "hw/sysbus.h"
>>> +#include "hw/devices.h"
>>> +#include "sysemu/sysemu.h"
>>> +
>>> +#include "faraday.h"
>>> +
>>> +#define REG_MCR             0x00    /* memory configuration register */
>>> +#define REG_MSR             0x04    /* memory status register */
>>> +#define REG_REVR            0x50    /* revision register */
>>> +
>>> +#define MSR_INIT_OK         BIT(8)  /* DDR2 initial is completed */
>>> +#define MSR_CMD_MRS         BIT(0)  /* start MRS command */
>>> +
>>> +#define CFG_REGSIZE         (0x50 / 4)
>>> +
>>> +#define TYPE_FTDDRII030     "ftddrii030"
>>> +
>>> +typedef struct Ftddrii030State {
>>> +    SysBusDevice busdev;
>>> +    MemoryRegion iomem;
>>> +
>>> +    FaradaySoCState *soc;
>>> +    /* HW register cache */
>>> +    uint32_t regs[CFG_REGSIZE];
>>> +} Ftddrii030State;
>>> +
>>> +#define FTDDRII030(obj) \
>>> +    OBJECT_CHECK(Ftddrii030State, obj, TYPE_FTDDRII030)
>>> +
>>> +#define DDR_REG32(s, off) \
>>> +    ((s)->regs[(off) / 4])
>>> +
>>> +static uint64_t
>>> +ftddrii030_mem_read(void *opaque, hwaddr addr, unsigned size)
>>> +{
>>> +    Ftddrii030State *s = FTDDRII030(opaque);
>>> +    uint64_t ret = 0;
>>> +
>>> +    if (s->soc->ddr_inited) {
>>> +        DDR_REG32(s, REG_MSR) |= MSR_INIT_OK;
>>> +    }
>>> +
>>> +    switch (addr) {
>>> +    case REG_MCR ... (CFG_REGSIZE - 1) * 4:
>>> +        ret = s->regs[addr / 4];
>>> +        break;
>>> +    case REG_REVR:
>>> +        ret = 0x100;    /* rev. = 0.1.0 */
>>> +        break;
>>> +    default:
>>> +        qemu_log_mask(LOG_GUEST_ERROR,
>>> +            "ftddrii030: undefined memory access@%#" HWADDR_PRIx "\n", addr);
>>> +        break;
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +static void
>>> +ftddrii030_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>>> +{
>>> +    Ftddrii030State *s = FTDDRII030(opaque);
>>> +
>>> +    switch (addr) {
>>> +    case REG_MCR:
>>> +        DDR_REG32(s, REG_MCR) = (uint32_t)val & 0xffff;
>>> +        break;
>>> +    case REG_MSR:
>>> +        val = (val & 0x3f) | (DDR_REG32(s, REG_MSR) & MSR_INIT_OK);
>>> +        if (!s->soc->ddr_inited && (val & MSR_CMD_MRS)) {
>>> +            val &= ~MSR_CMD_MRS;
>>> +            val |= MSR_INIT_OK;
>>> +            memory_region_add_subregion(s->soc->as,
>>> +                                        s->soc->ram_base,
>>> +                                        s->soc->ram);
>>
>> I feel like this is overstepping the bounds of the device. Its
>> modifying the internals of the parent device (the SoC itself). AFAICT,
>> this device does not need awareness of where the RAM is to live in the
>> address map, thats the responsibility of the machine model. It might
>> be cleaner to model the actual RAM as a second sysbus memory region
>> then leave it up the machine model to decide where in the address map
>> it should live. This device just adds/removes the ram from the second
>> region without knowing where it lives and the machine model maps the
>> RAM to its actual location. Keeps .as .ram_base and .ram private to
>> the SoC device.
>>
>
> Thanks for the comments,
> I'll try to implement a cleaner model in the way suggested in the
> above comments.
>
>>> +            s->soc->ddr_inited = true;
>>
>> I'm still trying to figure out the physical analogue of this. Is there
>> a genuine hardware linkage from the DDR controller to other devices
>> that says "hey i'm inited" or is this faking firmware activity? In the
>> former case, this ddr_inited should be a GPIO from DDR controller to
>> whatever devices care. In the latter case, its trickier, and we should
>> discuss bootloader based solutions to get your tiny little bit of
>> firmware in, without having to model non-existent hardware.
>>
>
> Thanks for the comments.
> It's the 1st one, it's used to inform the FTAHBC020 of the presence of
> DRAM in QEMU model. And thus it could be replaced by a GPIO
> implementation.

But what's the underlying transport mechanism for this information
this in silicon? Is there a wire from the DDR controller to the AHB
controller? Or is it some sort of other linkage? Do you have some
data-sheets for these two you could quickly link me? Might me able to
give a better suggestion with a quick scan of specs.

Regards,
Peter

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support
  2013-03-18  1:32       ` Peter Crosthwaite
@ 2013-03-18  9:56         ` Kuo-Jung Su
  2013-03-18 10:30           ` Peter Maydell
  0 siblings, 1 reply; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-18  9:56 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Igor Mitsyanko, qemu-devel, Blue Swirl, Paul Brook,
	Kuo-Jung Su, Andreas, fred konrad

2013/3/18 Peter Crosthwaite <peter.crosthwaite@xilinx.com>:
> On Mon, Mar 18, 2013 at 11:12 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>> 2013/3/16 Peter Crosthwaite <peter.crosthwaite@xilinx.com>:
>>> Hi Kuo-Jung,
>>>
>>> On Fri, Mar 15, 2013 at 11:13 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>>
>>>> The FTDDRII030 is a DDRII SDRAM controller which is responsible for
>>>> SDRAM initialization.
>>>> In QEMU we emulate only the SDRAM enable function.
>>>>
>>>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>> ---
>>>>  hw/arm/Makefile.objs      |    1 +
>>>>  hw/arm/faraday_a369_soc.c |    9 +++
>>>>  hw/arm/ftddrii030.c       |  183 +++++++++++++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 193 insertions(+)
>>>>  create mode 100644 hw/arm/ftddrii030.c
>>>>
>>>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>>>> index af36b01..0bbf838 100644
>>>> --- a/hw/arm/Makefile.objs
>>>> +++ b/hw/arm/Makefile.objs
>>>> @@ -39,3 +39,4 @@ obj-y += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
>>>>              faraday_a369_kpd.o
>>>>  obj-y += ftintc020.o
>>>>  obj-y += ftahbc020.o
>>>> +obj-y += ftddrii030.o
>>>> diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
>>>> index 01b4395..e8a63bb 100644
>>>> --- a/hw/arm/faraday_a369_soc.c
>>>> +++ b/hw/arm/faraday_a369_soc.c
>>>> @@ -158,6 +158,15 @@ a369soc_device_init(FaradaySoCState *s)
>>>>          fprintf(stderr, "a369soc: Unable to set soc link for FTAHBC020\n");
>>>>          abort();
>>>>      }
>>>> +
>>>> +    /* ftddrii030 */
>>>> +    ds = sysbus_create_simple("ftddrii030", 0x93100000, NULL);
>>>> +    s->ddrc = ds;
>>>> +    object_property_set_link(OBJECT(ds), OBJECT(s), "soc", &local_errp);
>>>> +    if (local_errp) {
>>>> +        fprintf(stderr, "a369soc: Unable to set soc link for FTDDRII030\n");
>>>> +        abort();
>>>> +    }
>>>>  }
>>>>
>>>>  static void a369soc_realize(DeviceState *dev, Error **errp)
>>>> diff --git a/hw/arm/ftddrii030.c b/hw/arm/ftddrii030.c
>>>> new file mode 100644
>>>> index 0000000..90a5842
>>>> --- /dev/null
>>>> +++ b/hw/arm/ftddrii030.c
>>>> @@ -0,0 +1,183 @@
>>>> +/*
>>>> + * Faraday DDRII controller
>>>> + *
>>>> + * Copyright (c) 2012 Faraday Technology
>>>> + * Written by Dante Su <dantesu@faraday-tech.com>
>>>> + *
>>>> + * This code is licensed under GNU GPL v2+
>>>> + */
>>>> +
>>>> +#include "hw/hw.h"
>>>> +#include "hw/sysbus.h"
>>>> +#include "hw/devices.h"
>>>> +#include "sysemu/sysemu.h"
>>>> +
>>>> +#include "faraday.h"
>>>> +
>>>> +#define REG_MCR             0x00    /* memory configuration register */
>>>> +#define REG_MSR             0x04    /* memory status register */
>>>> +#define REG_REVR            0x50    /* revision register */
>>>> +
>>>> +#define MSR_INIT_OK         BIT(8)  /* DDR2 initial is completed */
>>>> +#define MSR_CMD_MRS         BIT(0)  /* start MRS command */
>>>> +
>>>> +#define CFG_REGSIZE         (0x50 / 4)
>>>> +
>>>> +#define TYPE_FTDDRII030     "ftddrii030"
>>>> +
>>>> +typedef struct Ftddrii030State {
>>>> +    SysBusDevice busdev;
>>>> +    MemoryRegion iomem;
>>>> +
>>>> +    FaradaySoCState *soc;
>>>> +    /* HW register cache */
>>>> +    uint32_t regs[CFG_REGSIZE];
>>>> +} Ftddrii030State;
>>>> +
>>>> +#define FTDDRII030(obj) \
>>>> +    OBJECT_CHECK(Ftddrii030State, obj, TYPE_FTDDRII030)
>>>> +
>>>> +#define DDR_REG32(s, off) \
>>>> +    ((s)->regs[(off) / 4])
>>>> +
>>>> +static uint64_t
>>>> +ftddrii030_mem_read(void *opaque, hwaddr addr, unsigned size)
>>>> +{
>>>> +    Ftddrii030State *s = FTDDRII030(opaque);
>>>> +    uint64_t ret = 0;
>>>> +
>>>> +    if (s->soc->ddr_inited) {
>>>> +        DDR_REG32(s, REG_MSR) |= MSR_INIT_OK;
>>>> +    }
>>>> +
>>>> +    switch (addr) {
>>>> +    case REG_MCR ... (CFG_REGSIZE - 1) * 4:
>>>> +        ret = s->regs[addr / 4];
>>>> +        break;
>>>> +    case REG_REVR:
>>>> +        ret = 0x100;    /* rev. = 0.1.0 */
>>>> +        break;
>>>> +    default:
>>>> +        qemu_log_mask(LOG_GUEST_ERROR,
>>>> +            "ftddrii030: undefined memory access@%#" HWADDR_PRIx "\n", addr);
>>>> +        break;
>>>> +    }
>>>> +
>>>> +    return ret;
>>>> +}
>>>> +
>>>> +static void
>>>> +ftddrii030_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>>>> +{
>>>> +    Ftddrii030State *s = FTDDRII030(opaque);
>>>> +
>>>> +    switch (addr) {
>>>> +    case REG_MCR:
>>>> +        DDR_REG32(s, REG_MCR) = (uint32_t)val & 0xffff;
>>>> +        break;
>>>> +    case REG_MSR:
>>>> +        val = (val & 0x3f) | (DDR_REG32(s, REG_MSR) & MSR_INIT_OK);
>>>> +        if (!s->soc->ddr_inited && (val & MSR_CMD_MRS)) {
>>>> +            val &= ~MSR_CMD_MRS;
>>>> +            val |= MSR_INIT_OK;
>>>> +            memory_region_add_subregion(s->soc->as,
>>>> +                                        s->soc->ram_base,
>>>> +                                        s->soc->ram);
>>>
>>> I feel like this is overstepping the bounds of the device. Its
>>> modifying the internals of the parent device (the SoC itself). AFAICT,
>>> this device does not need awareness of where the RAM is to live in the
>>> address map, thats the responsibility of the machine model. It might
>>> be cleaner to model the actual RAM as a second sysbus memory region
>>> then leave it up the machine model to decide where in the address map
>>> it should live. This device just adds/removes the ram from the second
>>> region without knowing where it lives and the machine model maps the
>>> RAM to its actual location. Keeps .as .ram_base and .ram private to
>>> the SoC device.
>>>
>>
>> Thanks for the comments,
>> I'll try to implement a cleaner model in the way suggested in the
>> above comments.
>>
>>>> +            s->soc->ddr_inited = true;
>>>
>>> I'm still trying to figure out the physical analogue of this. Is there
>>> a genuine hardware linkage from the DDR controller to other devices
>>> that says "hey i'm inited" or is this faking firmware activity? In the
>>> former case, this ddr_inited should be a GPIO from DDR controller to
>>> whatever devices care. In the latter case, its trickier, and we should
>>> discuss bootloader based solutions to get your tiny little bit of
>>> firmware in, without having to model non-existent hardware.
>>>
>>
>> Thanks for the comments.
>> It's the 1st one, it's used to inform the FTAHBC020 of the presence of
>> DRAM in QEMU model. And thus it could be replaced by a GPIO
>> implementation.
>
> But what's the underlying transport mechanism for this information
> this in silicon? Is there a wire from the DDR controller to the AHB
> controller? Or is it some sort of other linkage? Do you have some
> data-sheets for these two you could quickly link me? Might me able to
> give a better suggestion with a quick scan of specs.
>

It's not an issue from the real hardware spec.

It's an issue about the RAM model remapping in QEMU.

The FTDDRII030 is responsible for SDRAM initialization.
Which means the DDRII SDRAM would not be stabilized until the
SDRAM is correctly initialized.
=>
In QEMU, the memory_region_add_subregion() is used to perform this emulation.


The FTAHBC030 is responsible for AHB device management (base + window size)
and also the special case for AHB remap of slave4 and slave6.
=>
In QEMU,
1. If SDRAM is initialized before activating AHB remap:
    memory_region_del_subregion() must be called prior to
memory_region_add_subregion().
    And this is the reason why I need '.ddr_inited' and
'.ahb_remapped' in SoC struct.
2. If SDRAM is not yet initialized while activating AHB remap:
    Only memory_region_add_subregion() needs to be invoked.

So there is no any underlying transport mechanism in the hardware.
It's simply about the way how I implement the model of HW emulation.

> Regards,
> Peter



--
Best wishes,
Kuo-Jung Su

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support
  2013-03-18  9:56         ` Kuo-Jung Su
@ 2013-03-18 10:30           ` Peter Maydell
  2013-03-19  5:15             ` Kuo-Jung Su
  0 siblings, 1 reply; 16+ messages in thread
From: Peter Maydell @ 2013-03-18 10:30 UTC (permalink / raw)
  To: Kuo-Jung Su
  Cc: Peter Crosthwaite, Igor Mitsyanko, qemu-devel, Blue Swirl,
	Paul Brook, Kuo-Jung Su, Andreas, fred konrad

On 18 March 2013 09:56, Kuo-Jung Su <dantesu@gmail.com> wrote:
> The FTDDRII030 is responsible for SDRAM initialization.
> Which means the DDRII SDRAM would not be stabilized until the
> SDRAM is correctly initialized.
> =>
> In QEMU, the memory_region_add_subregion() is used to perform this emulation.

If you want to model "sdram doesn't work unless it's inited"
(which is optional, often for qemu it's fine to just have
the RAM always work), then the right way to do this is
probably to have this device provide a memory region which
is a container and which the SoC always maps. Then this device
just maps the RAM into the container when the guest does the
DDR init. Having the device mess with its parent's address
space is a red flag that you're not modelling things right.

> The FTAHBC030 is responsible for AHB device management (base + window size)
> and also the special case for AHB remap of slave4 and slave6.
> =>
> In QEMU,
> 1. If SDRAM is initialized before activating AHB remap:
>     memory_region_del_subregion() must be called prior to
> memory_region_add_subregion().
>     And this is the reason why I need '.ddr_inited' and
> '.ahb_remapped' in SoC struct.
> 2. If SDRAM is not yet initialized while activating AHB remap:
>     Only memory_region_add_subregion() needs to be invoked.

If you're handling add/del subregion then you need to model
this so that the device that does the add/del is working on
a memory region container that it controls. Then it can have
a private data structure field which tracks what the state
of the mapped subregions is. This almost always turns out to
be the same way the hardware design is structured.

At the moment you have add/del going on in this device but
fields relating to what state the subregions are in are
at the top level soc state.

-- PMM

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support
  2013-03-18 10:30           ` Peter Maydell
@ 2013-03-19  5:15             ` Kuo-Jung Su
  0 siblings, 0 replies; 16+ messages in thread
From: Kuo-Jung Su @ 2013-03-19  5:15 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Peter Crosthwaite, Igor Mitsyanko, qemu-devel, Blue Swirl,
	Paul Brook, Kuo-Jung Su, Andreas, fred konrad

2013/3/18 Peter Maydell <peter.maydell@linaro.org>:
> On 18 March 2013 09:56, Kuo-Jung Su <dantesu@gmail.com> wrote:
>> The FTDDRII030 is responsible for SDRAM initialization.
>> Which means the DDRII SDRAM would not be stabilized until the
>> SDRAM is correctly initialized.
>> =>
>> In QEMU, the memory_region_add_subregion() is used to perform this emulation.
>
> If you want to model "sdram doesn't work unless it's inited"
> (which is optional, often for qemu it's fine to just have
> the RAM always work), then the right way to do this is
> probably to have this device provide a memory region which
> is a container and which the SoC always maps. Then this device
> just maps the RAM into the container when the guest does the
> DDR init. Having the device mess with its parent's address
> space is a red flag that you're not modelling things right.
>

Got it, thanks.
It sounds like a good idea to me, I'll try to model the ftddrii030 in that way.

>> The FTAHBC030 is responsible for AHB device management (base + window size)
>> and also the special case for AHB remap of slave4 and slave6.
>> =>
>> In QEMU,
>> 1. If SDRAM is initialized before activating AHB remap:
>>     memory_region_del_subregion() must be called prior to
>> memory_region_add_subregion().
>>     And this is the reason why I need '.ddr_inited' and
>> '.ahb_remapped' in SoC struct.
>> 2. If SDRAM is not yet initialized while activating AHB remap:
>>     Only memory_region_add_subregion() needs to be invoked.
>
> If you're handling add/del subregion then you need to model
> this so that the device that does the add/del is working on
> a memory region container that it controls. Then it can have
> a private data structure field which tracks what the state
> of the mapped subregions is. This almost always turns out to
> be the same way the hardware design is structured.
>
> At the moment you have add/del going on in this device but
> fields relating to what state the subregions are in are
> at the top level soc state.
>

Got it, thanks

> -- PMM



--
Best wishes,
Kuo-Jung Su

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2013-03-19  5:15 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-15 13:13 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 01/24] target-arm: add Faraday ARMv5TE processors support Kuo-Jung Su
2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 02/24] hw/arm: add Faraday a369 SoC platform support Kuo-Jung Su
2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 03/24] hw/arm: add FTINTC020 interrupt controller support Kuo-Jung Su
2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 04/24] hw/arm: add FTAHBC020 AHB " Kuo-Jung Su
2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII " Kuo-Jung Su
2013-03-16  3:32   ` Peter Crosthwaite
2013-03-18  1:12     ` Kuo-Jung Su
2013-03-18  1:32       ` Peter Crosthwaite
2013-03-18  9:56         ` Kuo-Jung Su
2013-03-18 10:30           ` Peter Maydell
2013-03-19  5:15             ` Kuo-Jung Su
2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 06/24] hw/arm: add FTPWMTMR010 timer support Kuo-Jung Su
2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 07/24] hw/arm: add FTWDT010 watchdog " Kuo-Jung Su
2013-03-15 13:13 ` [Qemu-devel] [PATCH v8 08/24] hw/arm: add FTRTC011 RTC " Kuo-Jung Su
  -- strict thread matches above, loose matches on Subject: below --
2013-03-15 13:15 [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
2013-03-15 13:15 ` [Qemu-devel] [PATCH v8 06/24] hw/arm: add FTPWMTMR010 timer support Kuo-Jung Su

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).