mirror of https://github.com/xemu-project/xemu.git
target-arm queue:
* virt: fix the virtual power button by adding a modelled "key press for 100ms" device * various improvements to m25p80 flash devices * implement new QMP query-gic-capability command to let the management layer know what versions of GIC we support -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJW+/87AAoJEDwlJe0UNgzeKowP/3L/X4iOsmd4liFUyMxtp4QX 7XeG3OfOPKn6H8R/PtHQFT5/s4pyIsVnt3l00itLSqF89cvMh1dIwS51EYkgr7IT G+kF4mPEfsaOGixDChrc4DgEE8DpqSXRaTSK/lX7E81ZXYiObMKlAe6oNbsQkDv8 vr6MDaPrNZPf4FlSiePyAwP4NuyHim1csRMHzXGMoGuAm/yZiAK9vtM58FfZHtt7 QFka7Kaly71sctxaCnDZJ3h+3UABTNDiFWwkWkVPA4IdWtB328iG7RLSuy2z5jgJ qIRPkUKwxXxAYzgqkHO5GmqB3No1Tm7NFyTf05Qvl9wlIMQqBYV0rA/EDLptlNUg M1DnXYR9mnyFt82TVeEAPJckyOvE2XSym74MFlwukOBxgaF7usYNvMTjPB/ix1th ZlkrrFAo7xsOltYpwiZDL1M+JCePspGMk7VlgKjMQutTzfJGwcPym9zaEJZhsQv9 Z6u0b8QhyEOoWOv3b3/8IGBy7Qrh1r34plqZDOKzp7q6Wrpx1q2mqhj0dyavLB+T uWKh10FcjeI/DyM+HhFdnrGQwLvdrWZVd8tRnVwEo164jkfZEe8bVbCbtFtHbeVx ++B7NVaDbjxF3c1vv7F4PyWz2F68Sa+Z+t2okK2+icBHtmqEVonH2zOOSgQymz+E 9QKHN2YogpQFq7m5YWt8 =mfnJ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160330-1' into staging target-arm queue: * virt: fix the virtual power button by adding a modelled "key press for 100ms" device * various improvements to m25p80 flash devices * implement new QMP query-gic-capability command to let the management layer know what versions of GIC we support # gpg: Signature made Wed 30 Mar 2016 17:30:51 BST using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" * remotes/pmaydell/tags/pull-target-arm-20160330-1: arm: implement query-gic-capabilities kvm: add kvm_device_supported() helper function arm: enhance kvm_arm_create_scratch_host_vcpu arm: qmp: add query-gic-capabilities interface block: m25p80: at25128a/at25256a models block: m25p80: n25q256a/n25q512a models block: m25p80: Implemented FSR register block: m25p80: Fast read and 4bytes commands block: m25p80: Dummy cycles for N25Q256/512 block: m25p80: Add configuration registers block: m25p80: 4byte address mode block: m25p80: Extend address mode block: m25p80: Widen flags variable block: m25p80: RESET_ENABLE and RESET_MEMORY commands block: m25p80: Removed unused variable ARM: Virt: Use gpio_key for power button hw/gpio: Add the emulation of gpio_key Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
4468d4e0f3
|
@ -111,3 +111,4 @@ CONFIG_I82801B11=y
|
|||
CONFIG_ACPI=y
|
||||
CONFIG_SMBIOS=y
|
||||
CONFIG_ASPEED_SOC=y
|
||||
CONFIG_GPIO_KEY=y
|
||||
|
|
|
@ -582,11 +582,11 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
|
|||
g_free(nodename);
|
||||
}
|
||||
|
||||
static DeviceState *pl061_dev;
|
||||
static DeviceState *gpio_key_dev;
|
||||
static void virt_powerdown_req(Notifier *n, void *opaque)
|
||||
{
|
||||
/* use gpio Pin 3 for power button event */
|
||||
qemu_set_irq(qdev_get_gpio_in(pl061_dev, 3), 1);
|
||||
qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
|
||||
}
|
||||
|
||||
static Notifier virt_system_powerdown_notifier = {
|
||||
|
@ -596,6 +596,7 @@ static Notifier virt_system_powerdown_notifier = {
|
|||
static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
{
|
||||
char *nodename;
|
||||
DeviceState *pl061_dev;
|
||||
hwaddr base = vbi->memmap[VIRT_GPIO].base;
|
||||
hwaddr size = vbi->memmap[VIRT_GPIO].size;
|
||||
int irq = vbi->irqmap[VIRT_GPIO];
|
||||
|
@ -618,6 +619,8 @@ static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
|
|||
qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "phandle", phandle);
|
||||
|
||||
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
|
||||
qdev_get_gpio_in(pl061_dev, 3));
|
||||
qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys");
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys", "compatible", "gpio-keys");
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#size-cells", 0);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "qemu/bitops.h"
|
||||
|
||||
#ifndef M25P80_ERR_DEBUG
|
||||
#define M25P80_ERR_DEBUG 0
|
||||
|
@ -46,7 +47,10 @@
|
|||
/* set to allow the page program command to write 0s back to 1. Useful for
|
||||
* modelling EEPROM with SPI flash command set
|
||||
*/
|
||||
#define WR_1 0x100
|
||||
#define EEPROM 0x100
|
||||
|
||||
/* 16 MiB max in 3 byte address mode */
|
||||
#define MAX_3BYTES_SIZE 0x1000000
|
||||
|
||||
typedef struct FlashPartInfo {
|
||||
const char *part_name;
|
||||
|
@ -61,7 +65,7 @@ typedef struct FlashPartInfo {
|
|||
uint32_t sector_size;
|
||||
uint32_t n_sectors;
|
||||
uint32_t page_size;
|
||||
uint8_t flags;
|
||||
uint16_t flags;
|
||||
} FlashPartInfo;
|
||||
|
||||
/* adapted from linux */
|
||||
|
@ -79,6 +83,30 @@ typedef struct FlashPartInfo {
|
|||
#define JEDEC_WINBOND 0xEF
|
||||
#define JEDEC_SPANSION 0x01
|
||||
|
||||
/* Numonyx (Micron) Configuration register macros */
|
||||
#define VCFG_DUMMY 0x1
|
||||
#define VCFG_WRAP_SEQUENTIAL 0x2
|
||||
#define NVCFG_XIP_MODE_DISABLED (7 << 9)
|
||||
#define NVCFG_XIP_MODE_MASK (7 << 9)
|
||||
#define VCFG_XIP_MODE_ENABLED (1 << 3)
|
||||
#define CFG_DUMMY_CLK_LEN 4
|
||||
#define NVCFG_DUMMY_CLK_POS 12
|
||||
#define VCFG_DUMMY_CLK_POS 4
|
||||
#define EVCFG_OUT_DRIVER_STRENGHT_DEF 7
|
||||
#define EVCFG_VPP_ACCELERATOR (1 << 3)
|
||||
#define EVCFG_RESET_HOLD_ENABLED (1 << 4)
|
||||
#define NVCFG_DUAL_IO_MASK (1 << 2)
|
||||
#define EVCFG_DUAL_IO_ENABLED (1 << 6)
|
||||
#define NVCFG_QUAD_IO_MASK (1 << 3)
|
||||
#define EVCFG_QUAD_IO_ENABLED (1 << 7)
|
||||
#define NVCFG_4BYTE_ADDR_MASK (1 << 0)
|
||||
#define NVCFG_LOWER_SEGMENT_MASK (1 << 1)
|
||||
#define CFG_UPPER_128MB_SEG_ENABLED 0x3
|
||||
|
||||
/* Numonyx (Micron) Flag Status Register macros */
|
||||
#define FSR_4BYTE_ADDR_MODE_ENABLED 0x1
|
||||
#define FSR_FLASH_READY (1 << 7)
|
||||
|
||||
static const FlashPartInfo known_devices[] = {
|
||||
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
|
||||
{ INFO("at25fs010", 0x1f6601, 0, 32 << 10, 4, ER_4K) },
|
||||
|
@ -95,6 +123,12 @@ static const FlashPartInfo known_devices[] = {
|
|||
|
||||
{ INFO("at45db081d", 0x1f2500, 0, 64 << 10, 16, ER_4K) },
|
||||
|
||||
/* Atmel EEPROMS - it is assumed, that don't care bit in command
|
||||
* is set to 0. Block protection is not supported.
|
||||
*/
|
||||
{ INFO("at25128a-nonjedec", 0x0, 0, 1, 131072, EEPROM) },
|
||||
{ INFO("at25256a-nonjedec", 0x0, 0, 1, 262144, EEPROM) },
|
||||
|
||||
/* EON -- en25xxx */
|
||||
{ INFO("en25f32", 0x1c3116, 0, 64 << 10, 64, ER_4K) },
|
||||
{ INFO("en25p32", 0x1c2016, 0, 64 << 10, 64, 0) },
|
||||
|
@ -206,8 +240,9 @@ static const FlashPartInfo known_devices[] = {
|
|||
{ INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
|
||||
{ INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K) },
|
||||
|
||||
/* Numonyx -- n25q128 */
|
||||
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
|
||||
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
||||
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
@ -218,21 +253,49 @@ typedef enum {
|
|||
WREN = 0x6,
|
||||
JEDEC_READ = 0x9f,
|
||||
BULK_ERASE = 0xc7,
|
||||
READ_FSR = 0x70,
|
||||
|
||||
READ = 0x3,
|
||||
FAST_READ = 0xb,
|
||||
READ = 0x03,
|
||||
READ4 = 0x13,
|
||||
FAST_READ = 0x0b,
|
||||
FAST_READ4 = 0x0c,
|
||||
DOR = 0x3b,
|
||||
DOR4 = 0x3c,
|
||||
QOR = 0x6b,
|
||||
QOR4 = 0x6c,
|
||||
DIOR = 0xbb,
|
||||
DIOR4 = 0xbc,
|
||||
QIOR = 0xeb,
|
||||
QIOR4 = 0xec,
|
||||
|
||||
PP = 0x2,
|
||||
PP = 0x02,
|
||||
PP4 = 0x12,
|
||||
DPP = 0xa2,
|
||||
QPP = 0x32,
|
||||
|
||||
ERASE_4K = 0x20,
|
||||
ERASE4_4K = 0x21,
|
||||
ERASE_32K = 0x52,
|
||||
ERASE_SECTOR = 0xd8,
|
||||
ERASE4_SECTOR = 0xdc,
|
||||
|
||||
EN_4BYTE_ADDR = 0xB7,
|
||||
EX_4BYTE_ADDR = 0xE9,
|
||||
|
||||
EXTEND_ADDR_READ = 0xC8,
|
||||
EXTEND_ADDR_WRITE = 0xC5,
|
||||
|
||||
RESET_ENABLE = 0x66,
|
||||
RESET_MEMORY = 0x99,
|
||||
|
||||
RNVCR = 0xB5,
|
||||
WNVCR = 0xB1,
|
||||
|
||||
RVCR = 0x85,
|
||||
WVCR = 0x81,
|
||||
|
||||
REVCR = 0x65,
|
||||
WEVCR = 0x61,
|
||||
} FlashCMD;
|
||||
|
||||
typedef enum {
|
||||
|
@ -246,8 +309,6 @@ typedef enum {
|
|||
typedef struct Flash {
|
||||
SSISlave parent_obj;
|
||||
|
||||
uint32_t r;
|
||||
|
||||
BlockBackend *blk;
|
||||
|
||||
uint8_t *storage;
|
||||
|
@ -261,7 +322,13 @@ typedef struct Flash {
|
|||
uint8_t needed_bytes;
|
||||
uint8_t cmd_in_progress;
|
||||
uint64_t cur_addr;
|
||||
uint32_t nonvolatile_cfg;
|
||||
uint32_t volatile_cfg;
|
||||
uint32_t enh_volatile_cfg;
|
||||
bool write_enable;
|
||||
bool four_bytes_address_mode;
|
||||
bool reset_enable;
|
||||
uint8_t ear;
|
||||
|
||||
int64_t dirty_page;
|
||||
|
||||
|
@ -333,6 +400,7 @@ static void flash_erase(Flash *s, int offset, FlashCMD cmd)
|
|||
|
||||
switch (cmd) {
|
||||
case ERASE_4K:
|
||||
case ERASE4_4K:
|
||||
len = 4 << 10;
|
||||
capa_to_assert = ER_4K;
|
||||
break;
|
||||
|
@ -341,6 +409,7 @@ static void flash_erase(Flash *s, int offset, FlashCMD cmd)
|
|||
capa_to_assert = ER_32K;
|
||||
break;
|
||||
case ERASE_SECTOR:
|
||||
case ERASE4_SECTOR:
|
||||
len = s->pi->sector_size;
|
||||
break;
|
||||
case BULK_ERASE:
|
||||
|
@ -387,7 +456,7 @@ void flash_write8(Flash *s, uint64_t addr, uint8_t data)
|
|||
" -> %" PRIx8 "\n", addr, prev, data);
|
||||
}
|
||||
|
||||
if (s->pi->flags & WR_1) {
|
||||
if (s->pi->flags & EEPROM) {
|
||||
s->storage[s->cur_addr] = data;
|
||||
} else {
|
||||
s->storage[s->cur_addr] &= data;
|
||||
|
@ -397,11 +466,43 @@ void flash_write8(Flash *s, uint64_t addr, uint8_t data)
|
|||
s->dirty_page = page;
|
||||
}
|
||||
|
||||
static inline int get_addr_length(Flash *s)
|
||||
{
|
||||
/* check if eeprom is in use */
|
||||
if (s->pi->flags == EEPROM) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
switch (s->cmd_in_progress) {
|
||||
case PP4:
|
||||
case READ4:
|
||||
case QIOR4:
|
||||
case ERASE4_4K:
|
||||
case ERASE4_SECTOR:
|
||||
case FAST_READ4:
|
||||
case DOR4:
|
||||
case QOR4:
|
||||
case DIOR4:
|
||||
return 4;
|
||||
default:
|
||||
return s->four_bytes_address_mode ? 4 : 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void complete_collecting_data(Flash *s)
|
||||
{
|
||||
s->cur_addr = s->data[0] << 16;
|
||||
s->cur_addr |= s->data[1] << 8;
|
||||
s->cur_addr |= s->data[2];
|
||||
int i;
|
||||
|
||||
s->cur_addr = 0;
|
||||
|
||||
for (i = 0; i < get_addr_length(s); ++i) {
|
||||
s->cur_addr <<= 8;
|
||||
s->cur_addr |= s->data[i];
|
||||
}
|
||||
|
||||
if (get_addr_length(s) == 3) {
|
||||
s->cur_addr += (s->ear & 0x3) * MAX_3BYTES_SIZE;
|
||||
}
|
||||
|
||||
s->state = STATE_IDLE;
|
||||
|
||||
|
@ -409,19 +510,28 @@ static void complete_collecting_data(Flash *s)
|
|||
case DPP:
|
||||
case QPP:
|
||||
case PP:
|
||||
case PP4:
|
||||
s->state = STATE_PAGE_PROGRAM;
|
||||
break;
|
||||
case READ:
|
||||
case READ4:
|
||||
case FAST_READ:
|
||||
case FAST_READ4:
|
||||
case DOR:
|
||||
case DOR4:
|
||||
case QOR:
|
||||
case QOR4:
|
||||
case DIOR:
|
||||
case DIOR4:
|
||||
case QIOR:
|
||||
case QIOR4:
|
||||
s->state = STATE_READ;
|
||||
break;
|
||||
case ERASE_4K:
|
||||
case ERASE4_4K:
|
||||
case ERASE_32K:
|
||||
case ERASE_SECTOR:
|
||||
case ERASE4_SECTOR:
|
||||
flash_erase(s, s->cur_addr, s->cmd_in_progress);
|
||||
break;
|
||||
case WRSR:
|
||||
|
@ -429,49 +539,128 @@ static void complete_collecting_data(Flash *s)
|
|||
s->write_enable = false;
|
||||
}
|
||||
break;
|
||||
case EXTEND_ADDR_WRITE:
|
||||
s->ear = s->data[0];
|
||||
break;
|
||||
case WNVCR:
|
||||
s->nonvolatile_cfg = s->data[0] | (s->data[1] << 8);
|
||||
break;
|
||||
case WVCR:
|
||||
s->volatile_cfg = s->data[0];
|
||||
break;
|
||||
case WEVCR:
|
||||
s->enh_volatile_cfg = s->data[0];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_memory(Flash *s)
|
||||
{
|
||||
s->cmd_in_progress = NOP;
|
||||
s->cur_addr = 0;
|
||||
s->ear = 0;
|
||||
s->four_bytes_address_mode = false;
|
||||
s->len = 0;
|
||||
s->needed_bytes = 0;
|
||||
s->pos = 0;
|
||||
s->state = STATE_IDLE;
|
||||
s->write_enable = false;
|
||||
s->reset_enable = false;
|
||||
|
||||
if (((s->pi->jedec >> 16) & 0xFF) == JEDEC_NUMONYX) {
|
||||
s->volatile_cfg = 0;
|
||||
s->volatile_cfg |= VCFG_DUMMY;
|
||||
s->volatile_cfg |= VCFG_WRAP_SEQUENTIAL;
|
||||
if ((s->nonvolatile_cfg & NVCFG_XIP_MODE_MASK)
|
||||
!= NVCFG_XIP_MODE_DISABLED) {
|
||||
s->volatile_cfg |= VCFG_XIP_MODE_ENABLED;
|
||||
}
|
||||
s->volatile_cfg |= deposit32(s->volatile_cfg,
|
||||
VCFG_DUMMY_CLK_POS,
|
||||
CFG_DUMMY_CLK_LEN,
|
||||
extract32(s->nonvolatile_cfg,
|
||||
NVCFG_DUMMY_CLK_POS,
|
||||
CFG_DUMMY_CLK_LEN)
|
||||
);
|
||||
|
||||
s->enh_volatile_cfg = 0;
|
||||
s->enh_volatile_cfg |= EVCFG_OUT_DRIVER_STRENGHT_DEF;
|
||||
s->enh_volatile_cfg |= EVCFG_VPP_ACCELERATOR;
|
||||
s->enh_volatile_cfg |= EVCFG_RESET_HOLD_ENABLED;
|
||||
if (s->nonvolatile_cfg & NVCFG_DUAL_IO_MASK) {
|
||||
s->enh_volatile_cfg |= EVCFG_DUAL_IO_ENABLED;
|
||||
}
|
||||
if (s->nonvolatile_cfg & NVCFG_QUAD_IO_MASK) {
|
||||
s->enh_volatile_cfg |= EVCFG_QUAD_IO_ENABLED;
|
||||
}
|
||||
if (!(s->nonvolatile_cfg & NVCFG_4BYTE_ADDR_MASK)) {
|
||||
s->four_bytes_address_mode = true;
|
||||
}
|
||||
if (!(s->nonvolatile_cfg & NVCFG_LOWER_SEGMENT_MASK)) {
|
||||
s->ear = CFG_UPPER_128MB_SEG_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
DB_PRINT_L(0, "Reset done.\n");
|
||||
}
|
||||
|
||||
static void decode_new_cmd(Flash *s, uint32_t value)
|
||||
{
|
||||
s->cmd_in_progress = value;
|
||||
DB_PRINT_L(0, "decoded new command:%x\n", value);
|
||||
|
||||
if (value != RESET_MEMORY) {
|
||||
s->reset_enable = false;
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
|
||||
case ERASE_4K:
|
||||
case ERASE4_4K:
|
||||
case ERASE_32K:
|
||||
case ERASE_SECTOR:
|
||||
case ERASE4_SECTOR:
|
||||
case READ:
|
||||
case READ4:
|
||||
case DPP:
|
||||
case QPP:
|
||||
case PP:
|
||||
s->needed_bytes = 3;
|
||||
case PP4:
|
||||
s->needed_bytes = get_addr_length(s);
|
||||
s->pos = 0;
|
||||
s->len = 0;
|
||||
s->state = STATE_COLLECTING_DATA;
|
||||
break;
|
||||
|
||||
case FAST_READ:
|
||||
case FAST_READ4:
|
||||
case DOR:
|
||||
case DOR4:
|
||||
case QOR:
|
||||
s->needed_bytes = 4;
|
||||
case QOR4:
|
||||
s->needed_bytes = get_addr_length(s);
|
||||
if (((s->pi->jedec >> 16) & 0xFF) == JEDEC_NUMONYX) {
|
||||
/* Dummy cycles modeled with bytes writes instead of bits */
|
||||
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
||||
}
|
||||
s->pos = 0;
|
||||
s->len = 0;
|
||||
s->state = STATE_COLLECTING_DATA;
|
||||
break;
|
||||
|
||||
case DIOR:
|
||||
case DIOR4:
|
||||
switch ((s->pi->jedec >> 16) & 0xFF) {
|
||||
case JEDEC_WINBOND:
|
||||
case JEDEC_SPANSION:
|
||||
s->needed_bytes = 4;
|
||||
break;
|
||||
case JEDEC_NUMONYX:
|
||||
default:
|
||||
s->needed_bytes = 5;
|
||||
s->needed_bytes = get_addr_length(s);
|
||||
/* Dummy cycles modeled with bytes writes instead of bits */
|
||||
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
||||
}
|
||||
s->pos = 0;
|
||||
s->len = 0;
|
||||
|
@ -479,14 +668,16 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||
break;
|
||||
|
||||
case QIOR:
|
||||
case QIOR4:
|
||||
switch ((s->pi->jedec >> 16) & 0xFF) {
|
||||
case JEDEC_WINBOND:
|
||||
case JEDEC_SPANSION:
|
||||
s->needed_bytes = 6;
|
||||
break;
|
||||
case JEDEC_NUMONYX:
|
||||
default:
|
||||
s->needed_bytes = 8;
|
||||
s->needed_bytes = get_addr_length(s);
|
||||
/* Dummy cycles modeled with bytes writes instead of bits */
|
||||
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
||||
}
|
||||
s->pos = 0;
|
||||
s->len = 0;
|
||||
|
@ -516,6 +707,16 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||
s->state = STATE_READING_DATA;
|
||||
break;
|
||||
|
||||
case READ_FSR:
|
||||
s->data[0] = FSR_FLASH_READY;
|
||||
if (s->four_bytes_address_mode) {
|
||||
s->data[0] |= FSR_4BYTE_ADDR_MODE_ENABLED;
|
||||
}
|
||||
s->pos = 0;
|
||||
s->len = 1;
|
||||
s->state = STATE_READING_DATA;
|
||||
break;
|
||||
|
||||
case JEDEC_READ:
|
||||
DB_PRINT_L(0, "populated jedec code\n");
|
||||
s->data[0] = (s->pi->jedec >> 16) & 0xff;
|
||||
|
@ -543,6 +744,77 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||
break;
|
||||
case NOP:
|
||||
break;
|
||||
case EN_4BYTE_ADDR:
|
||||
s->four_bytes_address_mode = true;
|
||||
break;
|
||||
case EX_4BYTE_ADDR:
|
||||
s->four_bytes_address_mode = false;
|
||||
break;
|
||||
case EXTEND_ADDR_READ:
|
||||
s->data[0] = s->ear;
|
||||
s->pos = 0;
|
||||
s->len = 1;
|
||||
s->state = STATE_READING_DATA;
|
||||
break;
|
||||
case EXTEND_ADDR_WRITE:
|
||||
if (s->write_enable) {
|
||||
s->needed_bytes = 1;
|
||||
s->pos = 0;
|
||||
s->len = 0;
|
||||
s->state = STATE_COLLECTING_DATA;
|
||||
}
|
||||
break;
|
||||
case RNVCR:
|
||||
s->data[0] = s->nonvolatile_cfg & 0xFF;
|
||||
s->data[1] = (s->nonvolatile_cfg >> 8) & 0xFF;
|
||||
s->pos = 0;
|
||||
s->len = 2;
|
||||
s->state = STATE_READING_DATA;
|
||||
break;
|
||||
case WNVCR:
|
||||
if (s->write_enable) {
|
||||
s->needed_bytes = 2;
|
||||
s->pos = 0;
|
||||
s->len = 0;
|
||||
s->state = STATE_COLLECTING_DATA;
|
||||
}
|
||||
break;
|
||||
case RVCR:
|
||||
s->data[0] = s->volatile_cfg & 0xFF;
|
||||
s->pos = 0;
|
||||
s->len = 1;
|
||||
s->state = STATE_READING_DATA;
|
||||
break;
|
||||
case WVCR:
|
||||
if (s->write_enable) {
|
||||
s->needed_bytes = 1;
|
||||
s->pos = 0;
|
||||
s->len = 0;
|
||||
s->state = STATE_COLLECTING_DATA;
|
||||
}
|
||||
break;
|
||||
case REVCR:
|
||||
s->data[0] = s->enh_volatile_cfg & 0xFF;
|
||||
s->pos = 0;
|
||||
s->len = 1;
|
||||
s->state = STATE_READING_DATA;
|
||||
break;
|
||||
case WEVCR:
|
||||
if (s->write_enable) {
|
||||
s->needed_bytes = 1;
|
||||
s->pos = 0;
|
||||
s->len = 0;
|
||||
s->state = STATE_COLLECTING_DATA;
|
||||
}
|
||||
break;
|
||||
case RESET_ENABLE:
|
||||
s->reset_enable = true;
|
||||
break;
|
||||
case RESET_MEMORY:
|
||||
if (s->reset_enable) {
|
||||
reset_memory(s);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
|
||||
break;
|
||||
|
@ -649,14 +921,26 @@ static int m25p80_init(SSISlave *ss)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void m25p80_reset(DeviceState *d)
|
||||
{
|
||||
Flash *s = M25P80(d);
|
||||
|
||||
reset_memory(s);
|
||||
}
|
||||
|
||||
static void m25p80_pre_save(void *opaque)
|
||||
{
|
||||
flash_sync_dirty((Flash *)opaque, -1);
|
||||
}
|
||||
|
||||
static Property m25p80_properties[] = {
|
||||
DEFINE_PROP_UINT32("nonvolatile-cfg", Flash, nonvolatile_cfg, 0x8FFF),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_m25p80 = {
|
||||
.name = "xilinx_spi",
|
||||
.version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = m25p80_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
|
@ -668,6 +952,12 @@ static const VMStateDescription vmstate_m25p80 = {
|
|||
VMSTATE_UINT8(cmd_in_progress, Flash),
|
||||
VMSTATE_UINT64(cur_addr, Flash),
|
||||
VMSTATE_BOOL(write_enable, Flash),
|
||||
VMSTATE_BOOL_V(reset_enable, Flash, 2),
|
||||
VMSTATE_UINT8_V(ear, Flash, 2),
|
||||
VMSTATE_BOOL_V(four_bytes_address_mode, Flash, 2),
|
||||
VMSTATE_UINT32_V(nonvolatile_cfg, Flash, 2),
|
||||
VMSTATE_UINT32_V(volatile_cfg, Flash, 2),
|
||||
VMSTATE_UINT32_V(enh_volatile_cfg, Flash, 2),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -683,6 +973,8 @@ static void m25p80_class_init(ObjectClass *klass, void *data)
|
|||
k->set_cs = m25p80_cs;
|
||||
k->cs_polarity = SSI_CS_LOW;
|
||||
dc->vmsd = &vmstate_m25p80;
|
||||
dc->props = m25p80_properties;
|
||||
dc->reset = m25p80_reset;
|
||||
mc->pi = data;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ common-obj-$(CONFIG_PL061) += pl061.o
|
|||
common-obj-$(CONFIG_PUV3) += puv3_gpio.o
|
||||
common-obj-$(CONFIG_ZAURUS) += zaurus.o
|
||||
common-obj-$(CONFIG_E500) += mpc8xxx.o
|
||||
common-obj-$(CONFIG_GPIO_KEY) += gpio_key.o
|
||||
|
||||
obj-$(CONFIG_OMAP) += omap_gpio.o
|
||||
obj-$(CONFIG_IMX) += imx_gpio.o
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* GPIO key
|
||||
*
|
||||
* Copyright (c) 2016 Linaro Limited
|
||||
*
|
||||
* Author: Shannon Zhao <shannon.zhao@linaro.org>
|
||||
*
|
||||
* Emulate a (human) keypress -- when the key is triggered by
|
||||
* setting the incoming gpio line, the outbound irq line is
|
||||
* raised for 100ms before being dropped again.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_GPIOKEY "gpio-key"
|
||||
#define GPIOKEY(obj) OBJECT_CHECK(GPIOKEYState, (obj), TYPE_GPIOKEY)
|
||||
#define GPIO_KEY_LATENCY 100 /* 100ms */
|
||||
|
||||
typedef struct GPIOKEYState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
QEMUTimer *timer;
|
||||
qemu_irq irq;
|
||||
} GPIOKEYState;
|
||||
|
||||
static const VMStateDescription vmstate_gpio_key = {
|
||||
.name = "gpio-key",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER_PTR(timer, GPIOKEYState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void gpio_key_reset(DeviceState *dev)
|
||||
{
|
||||
GPIOKEYState *s = GPIOKEY(dev);
|
||||
|
||||
timer_del(s->timer);
|
||||
}
|
||||
|
||||
static void gpio_key_timer_expired(void *opaque)
|
||||
{
|
||||
GPIOKEYState *s = (GPIOKEYState *)opaque;
|
||||
|
||||
qemu_set_irq(s->irq, 0);
|
||||
timer_del(s->timer);
|
||||
}
|
||||
|
||||
static void gpio_key_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
GPIOKEYState *s = (GPIOKEYState *)opaque;
|
||||
|
||||
qemu_set_irq(s->irq, 1);
|
||||
timer_mod(s->timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + GPIO_KEY_LATENCY);
|
||||
}
|
||||
|
||||
static void gpio_key_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
GPIOKEYState *s = GPIOKEY(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
qdev_init_gpio_in(dev, gpio_key_set_irq, 1);
|
||||
s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, gpio_key_timer_expired, s);
|
||||
}
|
||||
|
||||
static void gpio_key_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = gpio_key_realize;
|
||||
dc->vmsd = &vmstate_gpio_key;
|
||||
dc->reset = &gpio_key_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo gpio_key_info = {
|
||||
.name = TYPE_GPIOKEY,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(GPIOKEYState),
|
||||
.class_init = gpio_key_class_init,
|
||||
};
|
||||
|
||||
static void gpio_key_register_types(void)
|
||||
{
|
||||
type_register_static(&gpio_key_info);
|
||||
}
|
||||
|
||||
type_init(gpio_key_register_types)
|
|
@ -306,6 +306,15 @@ void kvm_device_access(int fd, int group, uint64_t attr,
|
|||
*/
|
||||
int kvm_create_device(KVMState *s, uint64_t type, bool test);
|
||||
|
||||
/**
|
||||
* kvm_device_supported - probe whether KVM supports specific device
|
||||
*
|
||||
* @vmfd: The fd handler for VM
|
||||
* @type: type of device
|
||||
*
|
||||
* @return: true if supported, otherwise false.
|
||||
*/
|
||||
bool kvm_device_supported(int vmfd, uint64_t type);
|
||||
|
||||
/* Arch specific hooks */
|
||||
|
||||
|
|
15
kvm-all.c
15
kvm-all.c
|
@ -2339,6 +2339,21 @@ int kvm_create_device(KVMState *s, uint64_t type, bool test)
|
|||
return test ? 0 : create_dev.fd;
|
||||
}
|
||||
|
||||
bool kvm_device_supported(int vmfd, uint64_t type)
|
||||
{
|
||||
struct kvm_create_device create_dev = {
|
||||
.type = type,
|
||||
.fd = -1,
|
||||
.flags = KVM_CREATE_DEVICE_TEST,
|
||||
};
|
||||
|
||||
if (ioctl(vmfd, KVM_CHECK_EXTENSION, KVM_CAP_DEVICE_CTRL) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (ioctl(vmfd, KVM_CREATE_DEVICE, &create_dev) >= 0);
|
||||
}
|
||||
|
||||
int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source)
|
||||
{
|
||||
struct kvm_one_reg reg;
|
||||
|
|
|
@ -4259,3 +4259,11 @@ void qmp_dump_skeys(const char *filename, Error **errp)
|
|||
error_setg(errp, QERR_FEATURE_DISABLED, "dump-skeys");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_ARM
|
||||
GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
|
||||
{
|
||||
error_setg(errp, QERR_FEATURE_DISABLED, "query-gic-capabilities");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -4134,3 +4134,39 @@
|
|||
##
|
||||
{ 'enum': 'ReplayMode',
|
||||
'data': [ 'none', 'record', 'play' ] }
|
||||
|
||||
##
|
||||
# @GICCapability:
|
||||
#
|
||||
# The struct describes capability for a specific GIC (Generic
|
||||
# Interrupt Controller) version. These bits are not only decided by
|
||||
# QEMU/KVM software version, but also decided by the hardware that
|
||||
# the program is running upon.
|
||||
#
|
||||
# @version: version of GIC to be described. Currently, only 2 and 3
|
||||
# are supported.
|
||||
#
|
||||
# @emulated: whether current QEMU/hardware supports emulated GIC
|
||||
# device in user space.
|
||||
#
|
||||
# @kernel: whether current QEMU/hardware supports hardware
|
||||
# accelerated GIC device in kernel.
|
||||
#
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'struct': 'GICCapability',
|
||||
'data': { 'version': 'int',
|
||||
'emulated': 'bool',
|
||||
'kernel': 'bool' } }
|
||||
|
||||
##
|
||||
# @query-gic-capabilities:
|
||||
#
|
||||
# This command is ARM-only. It will return a list of GICCapability
|
||||
# objects that describe its capability bits.
|
||||
#
|
||||
# Returns: a list of GICCapability objects.
|
||||
#
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
|
||||
|
|
|
@ -4853,3 +4853,30 @@ Example:
|
|||
{"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3840,
|
||||
"pop-vlan": 1, "id": 251658240}
|
||||
]}
|
||||
|
||||
EQMP
|
||||
|
||||
#if defined TARGET_ARM
|
||||
{
|
||||
.name = "query-gic-capabilities",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_query_gic_capabilities,
|
||||
},
|
||||
#endif
|
||||
|
||||
SQMP
|
||||
query-gic-capabilities
|
||||
---------------
|
||||
|
||||
Return a list of GICCapability objects, describing supported GIC
|
||||
(Generic Interrupt Controller) versions.
|
||||
|
||||
Arguments: None
|
||||
|
||||
Example:
|
||||
|
||||
-> { "execute": "query-gic-capabilities" }
|
||||
<- { "return": [{ "version": 2, "emulated": true, "kernel": false },
|
||||
{ "version": 3, "emulated": false, "kernel": true } ] }
|
||||
|
||||
EQMP
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
obj-y += arm-semi.o
|
||||
obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o
|
||||
obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o monitor.o
|
||||
obj-$(CONFIG_KVM) += kvm.o
|
||||
obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
|
||||
obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
|
||||
|
|
|
@ -62,13 +62,18 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (!init) {
|
||||
/* Caller doesn't want the VCPU to be initialized, so skip it */
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, init);
|
||||
if (ret >= 0) {
|
||||
ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
} else if (cpus_to_try) {
|
||||
/* Old kernel which doesn't know about the
|
||||
* PREFERRED_TARGET ioctl: we know it will only support
|
||||
* creating one kind of guest CPU which is its preferred
|
||||
|
@ -85,8 +90,15 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
|
|||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
/* Treat a NULL cpus_to_try argument the same as an empty
|
||||
* list, which means we will fail the call since this must
|
||||
* be an old kernel which doesn't support PREFERRED_TARGET.
|
||||
*/
|
||||
goto err;
|
||||
}
|
||||
|
||||
finish:
|
||||
fdarray[0] = kvmfd;
|
||||
fdarray[1] = vmfd;
|
||||
fdarray[2] = cpufd;
|
||||
|
|
|
@ -124,9 +124,12 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu);
|
|||
* kvm_arm_create_scratch_host_vcpu:
|
||||
* @cpus_to_try: array of QEMU_KVM_ARM_TARGET_* values (terminated with
|
||||
* QEMU_KVM_ARM_TARGET_NONE) to try as fallback if the kernel does not
|
||||
* know the PREFERRED_TARGET ioctl
|
||||
* know the PREFERRED_TARGET ioctl. Passing NULL is the same as passing
|
||||
* an empty array.
|
||||
* @fdarray: filled in with kvmfd, vmfd, cpufd file descriptors in that order
|
||||
* @init: filled in with the necessary values for creating a host vcpu
|
||||
* @init: filled in with the necessary values for creating a host
|
||||
* vcpu. If NULL is provided, will not init the vCPU (though the cpufd
|
||||
* will still be set up).
|
||||
*
|
||||
* Create a scratch vcpu in its own VM of the type preferred by the host
|
||||
* kernel (as would be used for '-cpu host'), for purposes of probing it
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* QEMU monitor.c for ARM.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "hw/boards.h"
|
||||
#include "kvm_arm.h"
|
||||
|
||||
static GICCapability *gic_cap_new(int version)
|
||||
{
|
||||
GICCapability *cap = g_new0(GICCapability, 1);
|
||||
cap->version = version;
|
||||
/* by default, support none */
|
||||
cap->emulated = false;
|
||||
cap->kernel = false;
|
||||
return cap;
|
||||
}
|
||||
|
||||
static GICCapabilityList *gic_cap_list_add(GICCapabilityList *head,
|
||||
GICCapability *cap)
|
||||
{
|
||||
GICCapabilityList *item = g_new0(GICCapabilityList, 1);
|
||||
item->value = cap;
|
||||
item->next = head;
|
||||
return item;
|
||||
}
|
||||
|
||||
static inline void gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
int fdarray[3];
|
||||
|
||||
if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test KVM GICv2 */
|
||||
if (kvm_device_supported(fdarray[1], KVM_DEV_TYPE_ARM_VGIC_V2)) {
|
||||
v2->kernel = true;
|
||||
}
|
||||
|
||||
/* Test KVM GICv3 */
|
||||
if (kvm_device_supported(fdarray[1], KVM_DEV_TYPE_ARM_VGIC_V3)) {
|
||||
v3->kernel = true;
|
||||
}
|
||||
|
||||
kvm_arm_destroy_scratch_host_vcpu(fdarray);
|
||||
#endif
|
||||
}
|
||||
|
||||
GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
|
||||
{
|
||||
GICCapabilityList *head = NULL;
|
||||
GICCapability *v2 = gic_cap_new(2), *v3 = gic_cap_new(3);
|
||||
|
||||
v2->emulated = true;
|
||||
/* TODO: we'd change to true after we get emulated GICv3. */
|
||||
v3->emulated = false;
|
||||
|
||||
gic_cap_kvm_probe(v2, v3);
|
||||
|
||||
head = gic_cap_list_add(head, v2);
|
||||
head = gic_cap_list_add(head, v3);
|
||||
|
||||
return head;
|
||||
}
|
Loading…
Reference in New Issue