* [Qemu-devel] Review : Musicpal qdev conversion and I2C bitbanging extraction @ 2009-08-10 19:01 Benoit Canet 2009-08-10 19:01 ` [Qemu-devel] [PATCH 1/3] Musicpal qdev conversion : gpio (except I2C part), keyboard and lcd Benoit Canet 0 siblings, 1 reply; 5+ messages in thread From: Benoit Canet @ 2009-08-10 19:01 UTC (permalink / raw) To: qemu-devel Hello, These patches rewrites the remaining devices of musipal.c to the qdev API in order to make a generic I2C GPIO bitbanging module. The goal is to be able to write a versatile I2C device using the I2C bitbanging module. Cleanup and improvements hints are welcome. Regards Benoit ^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 1/3] Musicpal qdev conversion : gpio (except I2C part), keyboard and lcd 2009-08-10 19:01 [Qemu-devel] Review : Musicpal qdev conversion and I2C bitbanging extraction Benoit Canet @ 2009-08-10 19:01 ` Benoit Canet 2009-08-10 19:01 ` [Qemu-devel] [PATCH 2/3] Extract musicpal.c I2C bitbanging code and make it gpio aware Benoit Canet 0 siblings, 1 reply; 5+ messages in thread From: Benoit Canet @ 2009-08-10 19:01 UTC (permalink / raw) To: qemu-devel; +Cc: Benoit Canet Signed-off-by: Benoit Canet <benoit.canet@gmail.com> --- hw/musicpal.c | 315 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 231 insertions(+), 84 deletions(-) diff --git a/hw/musicpal.c b/hw/musicpal.c index e636791..067c228 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -68,9 +68,6 @@ #define MP_RTC_IRQ 28 #define MP_AUDIO_IRQ 30 -static uint32_t gpio_in_state = 0xffffffff; -static uint32_t gpio_isr; -static uint32_t gpio_out_state; static ram_addr_t sram_off; typedef enum i2c_state { @@ -782,6 +779,7 @@ static void mv88w8618_eth_init(SysBusDevice *dev) typedef struct musicpal_lcd_state { SysBusDevice busdev; + uint32_t brightness; uint32_t mode; uint32_t irqctrl; int page; @@ -790,37 +788,15 @@ typedef struct musicpal_lcd_state { uint8_t video_ram[128*64/8]; } musicpal_lcd_state; -static uint32_t lcd_brightness; - -static uint8_t scale_lcd_color(uint8_t col) +static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col) { - int tmp = col; - - switch (lcd_brightness) { - case 0x00000007: /* 0 */ + switch (s->brightness) { + case 7: + return col; + case 0: return 0; - - case 0x00020000: /* 1 */ - return (tmp * 1) / 7; - - case 0x00020001: /* 2 */ - return (tmp * 2) / 7; - - case 0x00040000: /* 3 */ - return (tmp * 3) / 7; - - case 0x00010006: /* 4 */ - return (tmp * 4) / 7; - - case 0x00020005: /* 5 */ - return (tmp * 5) / 7; - - case 0x00040003: /* 6 */ - return (tmp * 6) / 7; - - case 0x00030004: /* 7 */ default: - return col; + return (col * s->brightness) / 7; } } @@ -851,9 +827,9 @@ static void lcd_refresh(void *opaque) return; #define LCD_REFRESH(depth, func) \ case depth: \ - col = func(scale_lcd_color((MP_LCD_TEXTCOLOR >> 16) & 0xff), \ - scale_lcd_color((MP_LCD_TEXTCOLOR >> 8) & 0xff), \ - scale_lcd_color(MP_LCD_TEXTCOLOR & 0xff)); \ + col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \ + scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \ + scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \ for (x = 0; x < 128; x++) \ for (y = 0; y < 64; y++) \ if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) \ @@ -877,6 +853,13 @@ static void lcd_invalidate(void *opaque) { } +static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level) +{ + musicpal_lcd_state *s = (musicpal_lcd_state *) opaque; + s->brightness &= ~(1 << irq); + s->brightness |= level << irq; +} + static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset) { musicpal_lcd_state *s = opaque; @@ -946,14 +929,17 @@ static void musicpal_lcd_init(SysBusDevice *dev) musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev); int iomemtype; + s->brightness = 7; + iomemtype = cpu_register_io_memory(musicpal_lcd_readfn, musicpal_lcd_writefn, s); sysbus_init_mmio(dev, MP_LCD_SIZE, iomemtype); - cpu_register_physical_memory(MP_LCD_BASE, MP_LCD_SIZE, iomemtype); s->ds = graphic_console_init(lcd_refresh, lcd_invalidate, NULL, NULL, s); qemu_console_resize(s->ds, 128*3, 64*3); + + qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3); } /* PIC register offsets */ @@ -1327,15 +1313,7 @@ static void mv88w8618_wlan_init(SysBusDevice *dev) #define MP_GPIO_ISR_HI 0x520 /* GPIO bits & masks */ -#define MP_GPIO_WHEEL_VOL (1 << 8) -#define MP_GPIO_WHEEL_VOL_INV (1 << 9) -#define MP_GPIO_WHEEL_NAV (1 << 10) -#define MP_GPIO_WHEEL_NAV_INV (1 << 11) #define MP_GPIO_LCD_BRIGHTNESS 0x00070000 -#define MP_GPIO_BTN_FAVORITS (1 << 19) -#define MP_GPIO_BTN_MENU (1 << 20) -#define MP_GPIO_BTN_VOLUME (1 << 21) -#define MP_GPIO_BTN_NAVIGATION (1 << 22) #define MP_GPIO_I2C_DATA_BIT 29 #define MP_GPIO_I2C_DATA (1 << MP_GPIO_I2C_DATA_BIT) #define MP_GPIO_I2C_CLOCK_BIT 30 @@ -1343,29 +1321,128 @@ static void mv88w8618_wlan_init(SysBusDevice *dev) /* LCD brightness bits in GPIO_OE_HI */ #define MP_OE_LCD_BRIGHTNESS 0x0007 +typedef struct musicpal_gpio_state { + SysBusDevice busdev; + uint32_t lcd_brightness; + uint32_t out_state; + uint32_t in_state; + uint32_t isr; + uint32_t key_released; + uint32_t keys_event; /* store the received key event */ + qemu_irq irq; + qemu_irq out[3]; +} musicpal_gpio_state; + +static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) { + int i; + uint32_t brightness; + + /* compute brightness ratio */ + switch (s->lcd_brightness) { + case 0x00000007: + brightness = 0; + break; + + case 0x00020000: + brightness = 1; + break; + + case 0x00020001: + brightness = 2; + break; + + case 0x00040000: + brightness = 3; + break; + + case 0x00010006: + brightness = 4; + break; + + case 0x00020005: + brightness = 5; + break; + + case 0x00040003: + brightness = 6; + break; + + case 0x00030004: + default: + brightness = 7; + } + + /* set lcd brightness GPIOs */ + for (i = 0; i <= 2; i++) + qemu_set_irq(s->out[i], (brightness >> i) & 1); + +} + +static void musicpal_gpio_keys_update(musicpal_gpio_state *s) +{ + int gpio_mask = 0; + + /* transform the key state for GPIO usage */ + gpio_mask |= (s->keys_event & 15) << 8; + gpio_mask |= ((s->keys_event >> 4) & 15) << 19; + + /* update GPIO state */ + if (s->key_released) { + s->in_state |= gpio_mask; + } else { + s->in_state &= ~gpio_mask; + s->isr = gpio_mask; + qemu_irq_raise(s->irq); + } +} + +static void musicpal_gpio_irq(void *opaque, int irq, int level) +{ + musicpal_gpio_state *s = (musicpal_gpio_state *) opaque; + + /* receives keys bits */ + if (irq <= 7) { + s->keys_event &= ~(1 << irq); + s->keys_event |= level << irq; + return; + } + + /* receives key press/release */ + if (irq == 8) { + s->key_released = level; + return; + } + + /* a key has been transmited */ + if (irq == 9 && level == 1) + musicpal_gpio_keys_update(s); +} + static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset) { + musicpal_gpio_state *s = (musicpal_gpio_state *) opaque; + switch (offset) { case MP_GPIO_OE_HI: /* used for LCD brightness control */ - return lcd_brightness & MP_OE_LCD_BRIGHTNESS; + return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS; case MP_GPIO_OUT_LO: - return gpio_out_state & 0xFFFF; + return s->out_state & 0xFFFF; case MP_GPIO_OUT_HI: - return gpio_out_state >> 16; + return s->out_state >> 16; case MP_GPIO_IN_LO: - return gpio_in_state & 0xFFFF; + return s->in_state & 0xFFFF; case MP_GPIO_IN_HI: /* Update received I2C data */ - gpio_in_state = (gpio_in_state & ~MP_GPIO_I2C_DATA) | + s->in_state = (s->in_state & ~MP_GPIO_I2C_DATA) | (i2c_get_data(mixer_i2c) << MP_GPIO_I2C_DATA_BIT); - return gpio_in_state >> 16; + return s->in_state >> 16; case MP_GPIO_ISR_LO: - return gpio_isr & 0xFFFF; + return s->isr & 0xFFFF; case MP_GPIO_ISR_HI: - return gpio_isr >> 16; + return s->isr >> 16; default: return 0; @@ -1375,22 +1452,25 @@ static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset) static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset, uint32_t value) { + musicpal_gpio_state *s = (musicpal_gpio_state *) opaque; switch (offset) { case MP_GPIO_OE_HI: /* used for LCD brightness control */ - lcd_brightness = (lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) | + s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) | (value & MP_OE_LCD_BRIGHTNESS); + musicpal_gpio_brightness_update(s); break; case MP_GPIO_OUT_LO: - gpio_out_state = (gpio_out_state & 0xFFFF0000) | (value & 0xFFFF); + s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF); break; case MP_GPIO_OUT_HI: - gpio_out_state = (gpio_out_state & 0xFFFF) | (value << 16); - lcd_brightness = (lcd_brightness & 0xFFFF) | - (gpio_out_state & MP_GPIO_LCD_BRIGHTNESS); + s->out_state = (s->out_state & 0xFFFF) | (value << 16); + s->lcd_brightness = (s->lcd_brightness & 0xFFFF) | + (s->out_state & MP_GPIO_LCD_BRIGHTNESS); + musicpal_gpio_brightness_update(s); i2c_state_update(mixer_i2c, - (gpio_out_state >> MP_GPIO_I2C_DATA_BIT) & 1, - (gpio_out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); + (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1, + (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); break; } @@ -1408,13 +1488,29 @@ static CPUWriteMemoryFunc *musicpal_gpio_writefn[] = { musicpal_gpio_write, }; -static void musicpal_gpio_init(void) +static void musicpal_gpio_reset(musicpal_gpio_state *s) +{ + s->in_state = 0xffffffff; + s->key_released = 0; + s->keys_event = 0; + s->isr = 0; +} + +static void musicpal_gpio_init(SysBusDevice *dev) { + musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev); int iomemtype; + sysbus_init_irq(dev, &s->irq); + iomemtype = cpu_register_io_memory(musicpal_gpio_readfn, - musicpal_gpio_writefn, NULL); - cpu_register_physical_memory(MP_GPIO_BASE, MP_GPIO_SIZE, iomemtype); + musicpal_gpio_writefn, s); + sysbus_init_mmio(dev, MP_GPIO_SIZE, iomemtype); + + musicpal_gpio_reset(s); + + qdev_init_gpio_out(&dev->qdev, s->out, 3); + qdev_init_gpio_in(&dev->qdev, musicpal_gpio_irq, 10); } /* Keyboard codes & masks */ @@ -1432,69 +1528,109 @@ static void musicpal_gpio_init(void) #define KEYCODE_LEFT 0x4b #define KEYCODE_RIGHT 0x4d +#define MP_KEY_WHEEL_VOL (1) +#define MP_KEY_WHEEL_VOL_INV (1 << 1) +#define MP_KEY_WHEEL_NAV (1 << 2) +#define MP_KEY_WHEEL_NAV_INV (1 << 3) +#define MP_KEY_BTN_FAVORITS (1 << 4) +#define MP_KEY_BTN_MENU (1 << 5) +#define MP_KEY_BTN_VOLUME (1 << 6) +#define MP_KEY_BTN_NAVIGATION (1 << 7) + +typedef struct musicpal_key_state { + SysBusDevice busdev; + uint32_t kbd_extended; + uint32_t keys_state; + qemu_irq out[10]; +} musicpal_key_state; + static void musicpal_key_event(void *opaque, int keycode) { - qemu_irq irq = opaque; + musicpal_key_state *s = (musicpal_key_state *) opaque; uint32_t event = 0; - static int kbd_extended; + int i; if (keycode == KEYCODE_EXTENDED) { - kbd_extended = 1; + s->kbd_extended = 1; return; } - if (kbd_extended) + if (s->kbd_extended) switch (keycode & KEY_CODE) { case KEYCODE_UP: - event = MP_GPIO_WHEEL_NAV | MP_GPIO_WHEEL_NAV_INV; + event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV; break; case KEYCODE_DOWN: - event = MP_GPIO_WHEEL_NAV; + event = MP_KEY_WHEEL_NAV; break; case KEYCODE_LEFT: - event = MP_GPIO_WHEEL_VOL | MP_GPIO_WHEEL_VOL_INV; + event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV; break; case KEYCODE_RIGHT: - event = MP_GPIO_WHEEL_VOL; + event = MP_KEY_WHEEL_VOL; break; } else { switch (keycode & KEY_CODE) { case KEYCODE_F: - event = MP_GPIO_BTN_FAVORITS; + event = MP_KEY_BTN_FAVORITS; break; case KEYCODE_TAB: - event = MP_GPIO_BTN_VOLUME; + event = MP_KEY_BTN_VOLUME; break; case KEYCODE_ENTER: - event = MP_GPIO_BTN_NAVIGATION; + event = MP_KEY_BTN_NAVIGATION; break; case KEYCODE_M: - event = MP_GPIO_BTN_MENU; + event = MP_KEY_BTN_MENU; break; } /* Do not repeat already pressed buttons */ - if (!(keycode & KEY_RELEASED) && !(gpio_in_state & event)) + if (!(keycode & KEY_RELEASED) && !(s->keys_state & event)) event = 0; } if (event) { + + /* transmit key event on GPIOS */ + for (i = 0; i <= 7; i++) + qemu_set_irq(s->out[i], (event >> i) & 1); + + /* handle key press/release */ if (keycode & KEY_RELEASED) { - gpio_in_state |= event; + s->keys_state |= event; + qemu_irq_raise(s->out[8]); } else { - gpio_in_state &= ~event; - gpio_isr = event; - qemu_irq_raise(irq); + s->keys_state &= ~event; + qemu_irq_lower(s->out[8]); } + + /* signal that a key event occured */ + qemu_irq_pulse(s->out[9]); } - kbd_extended = 0; + s->kbd_extended = 0; +} + +static void musicpal_key_init(SysBusDevice *dev) +{ + musicpal_key_state *s = FROM_SYSBUS(musicpal_key_state, dev); + + sysbus_init_mmio(dev, 0x0, 0); + + s->kbd_extended = 0; + s->keys_state = 0; + + /* 8 key event GPIO + 1 key press/release + 1 strobe */ + qdev_init_gpio_out(&dev->qdev, s->out, 10); + + qemu_add_kbd_event_handler(musicpal_key_event, s); } static struct arm_boot_info musicpal_binfo = { @@ -1511,6 +1647,8 @@ static void musicpal_init(ram_addr_t ram_size, qemu_irq *cpu_pic; qemu_irq pic[32]; DeviceState *dev; + DeviceState *lcd_dev; + DeviceState *key_dev; int i; int index; unsigned long flash_size; @@ -1572,10 +1710,6 @@ static void musicpal_init(ram_addr_t ram_size, } sysbus_create_simple("mv88w8618_flashcfg", MP_FLASHCFG_BASE, NULL); - sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); - - qemu_add_kbd_event_handler(musicpal_key_event, pic[MP_GPIO_IRQ]); - qemu_check_nic_model(&nd_table[0], "mv88w8618"); dev = qdev_create(NULL, "mv88w8618_eth"); dev->nd = &nd_table[0]; @@ -1588,7 +1722,16 @@ static void musicpal_init(ram_addr_t ram_size, sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL); musicpal_misc_init(); - musicpal_gpio_init(); + + dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); + lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); + key_dev = sysbus_create_simple("musicpal_key", 0, NULL); + + for (i = 0; i < 3; i++) + qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i)); + + for (i = 0; i < 10; i++) + qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i)); musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; musicpal_binfo.kernel_filename = kernel_filename; @@ -1624,6 +1767,10 @@ static void musicpal_register_devices(void) mv88w8618_wlan_init); sysbus_register_dev("musicpal_lcd", sizeof(musicpal_lcd_state), musicpal_lcd_init); + sysbus_register_dev("musicpal_gpio", sizeof(musicpal_gpio_state), + musicpal_gpio_init); + sysbus_register_dev("musicpal_key", sizeof(musicpal_key_state), + musicpal_key_init); } device_init(musicpal_register_devices) -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 2/3] Extract musicpal.c I2C bitbanging code and make it gpio aware 2009-08-10 19:01 ` [Qemu-devel] [PATCH 1/3] Musicpal qdev conversion : gpio (except I2C part), keyboard and lcd Benoit Canet @ 2009-08-10 19:01 ` Benoit Canet 2009-08-10 19:01 ` [Qemu-devel] [PATCH 3/3] Make musicpal.c use the generic bitbang I2C device Benoit Canet 0 siblings, 1 reply; 5+ messages in thread From: Benoit Canet @ 2009-08-10 19:01 UTC (permalink / raw) To: qemu-devel; +Cc: Benoit Canet Signed-off-by: Benoit Canet <benoit.canet@gmail.com> --- Makefile.target | 2 +- hw/bitbang_i2c.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 1 deletions(-) create mode 100644 hw/bitbang_i2c.c diff --git a/Makefile.target b/Makefile.target index f9cd42a..12fcf21 100644 --- a/Makefile.target +++ b/Makefile.target @@ -592,7 +592,7 @@ obj-arm-y += omap2.o omap_dss.o soc_dma.o obj-arm-y += omap_sx1.o palm.o tsc210x.o obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o obj-arm-y += mst_fpga.o mainstone.o -obj-arm-y += musicpal.o pflash_cfi02.o +obj-arm-y += musicpal.o pflash_cfi02.o bitbang_i2c.o obj-arm-y += framebuffer.o obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c new file mode 100644 index 0000000..b1fe014 --- /dev/null +++ b/hw/bitbang_i2c.c @@ -0,0 +1,183 @@ +/* + * Bit-Bang i2c emulation extracted from + * Marvell MV88W8618 / Freecom MusicPal emulation. + * + * Copyright (c) 2008 Jan Kiszka + * + * This code is licenced under the GNU GPL v2. + */ +#include "hw.h" +#include "i2c.h" +#include "sysbus.h" + +typedef enum bitbang_i2c_state { + STOPPED = 0, + INITIALIZING, + SENDING_BIT7, + SENDING_BIT6, + SENDING_BIT5, + SENDING_BIT4, + SENDING_BIT3, + SENDING_BIT2, + SENDING_BIT1, + SENDING_BIT0, + WAITING_FOR_ACK, + RECEIVING_BIT7, + RECEIVING_BIT6, + RECEIVING_BIT5, + RECEIVING_BIT4, + RECEIVING_BIT3, + RECEIVING_BIT2, + RECEIVING_BIT1, + RECEIVING_BIT0, + SENDING_ACK +} bitbang_i2c_state; + +typedef struct bitbang_i2c_interface { + SysBusDevice busdev; + i2c_bus *bus; + bitbang_i2c_state state; + int last_data; + int last_clock; + uint8_t buffer; + int current_addr; + qemu_irq out; +} bitbang_i2c_interface; + +static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c) +{ + if (i2c->current_addr >= 0) + i2c_end_transfer(i2c->bus); + i2c->current_addr = -1; + i2c->state = STOPPED; +} + +static void bitbang_i2c_gpio_set(void *opaque, int irq, int level) +{ + bitbang_i2c_interface *i2c = opaque; + int data; + int clock; + int data_goes_up; + int data_goes_down; + int clock_goes_up; + int clock_goes_down; + + /* get pins states */ + data = i2c->last_data; + clock = i2c->last_clock; + + if (irq == 0) + data = level; + if (irq == 1) + clock = level; + + /* compute pins changes */ + data_goes_up = data == 1 && i2c->last_data == 0; + data_goes_down = data == 0 && i2c->last_data == 1; + clock_goes_up = clock == 1 && i2c->last_clock == 0; + clock_goes_down = clock == 0 && i2c->last_clock == 1; + + if (data_goes_up == 0 && data_goes_down == 0 && + clock_goes_up == 0 && clock_goes_down == 0) + return; + + if (!i2c) + return; + + switch (i2c->state) { + case STOPPED: + if (data_goes_down && clock == 1) + i2c->state = INITIALIZING; + break; + + case INITIALIZING: + if (clock_goes_down && data == 0) + i2c->state = SENDING_BIT7; + else + bitbang_i2c_enter_stop(i2c); + break; + + case SENDING_BIT7 ... SENDING_BIT0: + if (clock_goes_down) { + i2c->buffer = (i2c->buffer << 1) | data; + /* will end up in WAITING_FOR_ACK */ + i2c->state++; + } else if (data_goes_up && clock == 1) + bitbang_i2c_enter_stop(i2c); + break; + + case WAITING_FOR_ACK: + if (clock_goes_down) { + if (i2c->current_addr < 0) { + i2c->current_addr = i2c->buffer; + i2c_start_transfer(i2c->bus, (i2c->current_addr & 0xfe) / 2, + i2c->buffer & 1); + } else + i2c_send(i2c->bus, i2c->buffer); + if (i2c->current_addr & 1) { + i2c->state = RECEIVING_BIT7; + i2c->buffer = i2c_recv(i2c->bus); + } else + i2c->state = SENDING_BIT7; + } else if (data_goes_up && clock == 1) + bitbang_i2c_enter_stop(i2c); + break; + + case RECEIVING_BIT7 ... RECEIVING_BIT0: + if (clock_goes_down) { + /* will end up in SENDING_ACK */ + i2c->state++; + i2c->buffer <<= 1; + } else if (data_goes_up && clock == 1) + bitbang_i2c_enter_stop(i2c); + break; + + case SENDING_ACK: + if (clock_goes_down) { + i2c->state = RECEIVING_BIT7; + if (data == 0) + i2c->buffer = i2c_recv(i2c->bus); + else + i2c_nack(i2c->bus); + } else if (data_goes_up && clock == 1) + bitbang_i2c_enter_stop(i2c); + break; + } + + /* update output GPIO */ + switch (i2c->state) { + case RECEIVING_BIT7 ... RECEIVING_BIT0: + qemu_set_irq(i2c->out, i2c->buffer >> 7); + case WAITING_FOR_ACK: + default: + qemu_set_irq(i2c->out, 0); + } + + i2c->last_data = data; + i2c->last_clock = clock; +} + +static void bitbang_i2c_init(SysBusDevice *dev) +{ + bitbang_i2c_interface *s = FROM_SYSBUS(bitbang_i2c_interface, dev); + i2c_bus *bus; + + sysbus_init_mmio(dev, 0x0, 0); + + bus = i2c_init_bus(&dev->qdev, "i2c"); + s->bus = bus; + + s->last_data = 1; + s->last_clock = 1; + + qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2); + qdev_init_gpio_out(&dev->qdev, &s->out, 1); +} + +static void bitbang_i2c_register(void) +{ + sysbus_register_dev("bitbang_i2c", + sizeof(bitbang_i2c_interface), bitbang_i2c_init); +} + +device_init(bitbang_i2c_register) -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 3/3] Make musicpal.c use the generic bitbang I2C device 2009-08-10 19:01 ` [Qemu-devel] [PATCH 2/3] Extract musicpal.c I2C bitbanging code and make it gpio aware Benoit Canet @ 2009-08-10 19:01 ` Benoit Canet 2009-08-10 19:47 ` Filip Navara 0 siblings, 1 reply; 5+ messages in thread From: Benoit Canet @ 2009-08-10 19:01 UTC (permalink / raw) To: qemu-devel; +Cc: Benoit Canet Signed-off-by: Benoit Canet <benoit.canet@gmail.com> --- hw/musicpal.c | 226 +++++++++++++++++---------------------------------------- 1 files changed, 67 insertions(+), 159 deletions(-) diff --git a/hw/musicpal.c b/hw/musicpal.c index 067c228..e36b0dc 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -70,132 +70,6 @@ static ram_addr_t sram_off; -typedef enum i2c_state { - STOPPED = 0, - INITIALIZING, - SENDING_BIT7, - SENDING_BIT6, - SENDING_BIT5, - SENDING_BIT4, - SENDING_BIT3, - SENDING_BIT2, - SENDING_BIT1, - SENDING_BIT0, - WAITING_FOR_ACK, - RECEIVING_BIT7, - RECEIVING_BIT6, - RECEIVING_BIT5, - RECEIVING_BIT4, - RECEIVING_BIT3, - RECEIVING_BIT2, - RECEIVING_BIT1, - RECEIVING_BIT0, - SENDING_ACK -} i2c_state; - -typedef struct i2c_interface { - i2c_bus *bus; - i2c_state state; - int last_data; - int last_clock; - uint8_t buffer; - int current_addr; -} i2c_interface; - -static void i2c_enter_stop(i2c_interface *i2c) -{ - if (i2c->current_addr >= 0) - i2c_end_transfer(i2c->bus); - i2c->current_addr = -1; - i2c->state = STOPPED; -} - -static void i2c_state_update(i2c_interface *i2c, int data, int clock) -{ - if (!i2c) - return; - - switch (i2c->state) { - case STOPPED: - if (data == 0 && i2c->last_data == 1 && clock == 1) - i2c->state = INITIALIZING; - break; - - case INITIALIZING: - if (clock == 0 && i2c->last_clock == 1 && data == 0) - i2c->state = SENDING_BIT7; - else - i2c_enter_stop(i2c); - break; - - case SENDING_BIT7 ... SENDING_BIT0: - if (clock == 0 && i2c->last_clock == 1) { - i2c->buffer = (i2c->buffer << 1) | data; - i2c->state++; /* will end up in WAITING_FOR_ACK */ - } else if (data == 1 && i2c->last_data == 0 && clock == 1) - i2c_enter_stop(i2c); - break; - - case WAITING_FOR_ACK: - if (clock == 0 && i2c->last_clock == 1) { - if (i2c->current_addr < 0) { - i2c->current_addr = i2c->buffer; - i2c_start_transfer(i2c->bus, i2c->current_addr & 0xfe, - i2c->buffer & 1); - } else - i2c_send(i2c->bus, i2c->buffer); - if (i2c->current_addr & 1) { - i2c->state = RECEIVING_BIT7; - i2c->buffer = i2c_recv(i2c->bus); - } else - i2c->state = SENDING_BIT7; - } else if (data == 1 && i2c->last_data == 0 && clock == 1) - i2c_enter_stop(i2c); - break; - - case RECEIVING_BIT7 ... RECEIVING_BIT0: - if (clock == 0 && i2c->last_clock == 1) { - i2c->state++; /* will end up in SENDING_ACK */ - i2c->buffer <<= 1; - } else if (data == 1 && i2c->last_data == 0 && clock == 1) - i2c_enter_stop(i2c); - break; - - case SENDING_ACK: - if (clock == 0 && i2c->last_clock == 1) { - i2c->state = RECEIVING_BIT7; - if (data == 0) - i2c->buffer = i2c_recv(i2c->bus); - else - i2c_nack(i2c->bus); - } else if (data == 1 && i2c->last_data == 0 && clock == 1) - i2c_enter_stop(i2c); - break; - } - - i2c->last_data = data; - i2c->last_clock = clock; -} - -static int i2c_get_data(i2c_interface *i2c) -{ - if (!i2c) - return 0; - - switch (i2c->state) { - case RECEIVING_BIT7 ... RECEIVING_BIT0: - return (i2c->buffer >> 7); - - case WAITING_FOR_ACK: - default: - return 0; - } -} - -static i2c_interface *mixer_i2c; - -#ifdef HAS_AUDIO - /* Audio register offsets */ #define MP_AUDIO_PLAYBACK_MODE 0x00 #define MP_AUDIO_CLOCK_DIV 0x18 @@ -219,9 +93,9 @@ static i2c_interface *mixer_i2c; /* Wolfson 8750 I2C address */ #define MP_WM_ADDR 0x34 -static const char audio_name[] = "mv88w8618"; - +#ifdef HAS_AUDIO typedef struct musicpal_audio_state { + SysBusDevice busdev; qemu_irq irq; uint32_t playback_mode; uint32_t status; @@ -235,7 +109,7 @@ typedef struct musicpal_audio_state { DeviceState *wm; } musicpal_audio_state; -static void audio_callback(void *opaque, int free_out, int free_in) +static void musicpal_audio_callback(void *opaque, int free_out, int free_in) { musicpal_audio_state *s = opaque; int16_t *codec_buffer; @@ -418,36 +292,36 @@ static CPUWriteMemoryFunc *musicpal_audio_writefn[] = { musicpal_audio_write }; -static i2c_interface *musicpal_audio_init(qemu_irq irq) +static void musicpal_audio_init(SysBusDevice *dev) { - musicpal_audio_state *s; - i2c_interface *i2c; + musicpal_audio_state *s = FROM_SYSBUS(musicpal_audio_state, dev); int iomemtype; - s = qemu_mallocz(sizeof(musicpal_audio_state)); - s->irq = irq; - - i2c = qemu_mallocz(sizeof(i2c_interface)); - i2c->bus = i2c_init_bus(NULL, "i2c"); - i2c->current_addr = -1; + sysbus_init_irq(dev, &s->irq); - s->wm = i2c_create_slave(i2c->bus, "wm8750", MP_WM_ADDR); - wm8750_data_req_set(s->wm, audio_callback, s); + wm8750_data_req_set(s->wm, musicpal_audio_callback, s); iomemtype = cpu_register_io_memory(musicpal_audio_readfn, - musicpal_audio_writefn, s); - cpu_register_physical_memory(MP_AUDIO_BASE, MP_AUDIO_SIZE, iomemtype); + musicpal_audio_writefn, s); + sysbus_init_mmio(dev, MP_AUDIO_SIZE, iomemtype); qemu_register_reset(musicpal_audio_reset, s); - - return i2c; -} -#else /* !HAS_AUDIO */ -static i2c_interface *musicpal_audio_init(qemu_irq irq) -{ - return NULL; } -#endif /* !HAS_AUDIO */ + +static SysBusDeviceInfo musicpal_audio_info = { + .init = musicpal_audio_init, + .qdev.name = "musicpal_audio", + .qdev.size = sizeof(musicpal_audio_state), + .qdev.props = (Property[]) { + { + .name = "wm8750", + .info = &qdev_prop_ptr, + .offset = offsetof(musicpal_audio_state, wm), + }, + {/* end of list */} + } +}; +#endif /* Ethernet register offsets */ #define MP_ETH_SMIR 0x010 @@ -1327,10 +1201,11 @@ typedef struct musicpal_gpio_state { uint32_t out_state; uint32_t in_state; uint32_t isr; + uint32_t i2c_read_data; uint32_t key_released; uint32_t keys_event; /* store the received key event */ qemu_irq irq; - qemu_irq out[3]; + qemu_irq out[5]; } musicpal_gpio_state; static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) { @@ -1400,6 +1275,10 @@ static void musicpal_gpio_irq(void *opaque, int irq, int level) { musicpal_gpio_state *s = (musicpal_gpio_state *) opaque; + if (irq == 10) { + s->i2c_read_data = level; + } + /* receives keys bits */ if (irq <= 7) { s->keys_event &= ~(1 << irq); @@ -1436,7 +1315,7 @@ static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset) case MP_GPIO_IN_HI: /* Update received I2C data */ s->in_state = (s->in_state & ~MP_GPIO_I2C_DATA) | - (i2c_get_data(mixer_i2c) << MP_GPIO_I2C_DATA_BIT); + (s->i2c_read_data << MP_GPIO_I2C_DATA_BIT); return s->in_state >> 16; case MP_GPIO_ISR_LO: @@ -1468,9 +1347,8 @@ static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset, s->lcd_brightness = (s->lcd_brightness & 0xFFFF) | (s->out_state & MP_GPIO_LCD_BRIGHTNESS); musicpal_gpio_brightness_update(s); - i2c_state_update(mixer_i2c, - (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1, - (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); + qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1); + qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); break; } @@ -1491,6 +1369,7 @@ static CPUWriteMemoryFunc *musicpal_gpio_writefn[] = { static void musicpal_gpio_reset(musicpal_gpio_state *s) { s->in_state = 0xffffffff; + s->i2c_read_data = 1; s->key_released = 0; s->keys_event = 0; s->isr = 0; @@ -1509,8 +1388,10 @@ static void musicpal_gpio_init(SysBusDevice *dev) musicpal_gpio_reset(s); - qdev_init_gpio_out(&dev->qdev, s->out, 3); - qdev_init_gpio_in(&dev->qdev, musicpal_gpio_irq, 10); + /* 3 brightness out + 2 lcd (data and clock ) */ + qdev_init_gpio_out(&dev->qdev, s->out, 5); + /* 10 gpio button input + 1 I2C data input */ + qdev_init_gpio_in(&dev->qdev, musicpal_gpio_irq, 11); } /* Keyboard codes & masks */ @@ -1647,8 +1528,14 @@ static void musicpal_init(ram_addr_t ram_size, qemu_irq *cpu_pic; qemu_irq pic[32]; DeviceState *dev; + DeviceState *i2c_dev; DeviceState *lcd_dev; DeviceState *key_dev; +#ifdef HAS_AUDIO + DeviceState *wm8750_dev; + SysBusDevice *s; +#endif + i2c_bus *i2c; int i; int index; unsigned long flash_size; @@ -1717,22 +1604,40 @@ static void musicpal_init(ram_addr_t ram_size, sysbus_mmio_map(sysbus_from_qdev(dev), 0, MP_ETH_BASE); sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[MP_ETH_IRQ]); - mixer_i2c = musicpal_audio_init(pic[MP_AUDIO_IRQ]); - sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL); musicpal_misc_init(); dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); + i2c_dev = sysbus_create_simple("bitbang_i2c", 0, NULL); + i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"); + lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); key_dev = sysbus_create_simple("musicpal_key", 0, NULL); + /* I2C read data */ + qdev_connect_gpio_out(i2c_dev, 0, qdev_get_gpio_in(dev, 10)); + /* I2C data */ + qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0)); + /* I2C clock */ + qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1)); + for (i = 0; i < 3; i++) qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i)); for (i = 0; i < 10; i++) qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i)); +#ifdef HAS_AUDIO + wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR); + dev = qdev_create(NULL, "musicpal_audio"); + s = sysbus_from_qdev(dev); + qdev_prop_set_ptr(dev, "wm8750", wm8750_dev); + qdev_init(dev); + sysbus_mmio_map(s, 0, MP_AUDIO_BASE); + sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); +#endif + musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; musicpal_binfo.kernel_filename = kernel_filename; musicpal_binfo.kernel_cmdline = kernel_cmdline; @@ -1771,6 +1676,9 @@ static void musicpal_register_devices(void) musicpal_gpio_init); sysbus_register_dev("musicpal_key", sizeof(musicpal_key_state), musicpal_key_init); +#ifdef HAS_AUDIO + sysbus_register_withprop(&musicpal_audio_info); +#endif } device_init(musicpal_register_devices) -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH 3/3] Make musicpal.c use the generic bitbang I2C device 2009-08-10 19:01 ` [Qemu-devel] [PATCH 3/3] Make musicpal.c use the generic bitbang I2C device Benoit Canet @ 2009-08-10 19:47 ` Filip Navara 0 siblings, 0 replies; 5+ messages in thread From: Filip Navara @ 2009-08-10 19:47 UTC (permalink / raw) To: Benoit Canet; +Cc: qemu-devel On Mon, Aug 10, 2009 at 9:01 PM, Benoit Canet<benoit.canet@gmail.com> wrote: > > Signed-off-by: Benoit Canet <benoit.canet@gmail.com> I'd prefer the wm8750 audio emulation to be extracted to separate file and included as separate patch, much like you did with the bitbang_i2c device. This device is not really musicpal specific. Best regards, Filip Navara ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-08-10 19:47 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-08-10 19:01 [Qemu-devel] Review : Musicpal qdev conversion and I2C bitbanging extraction Benoit Canet 2009-08-10 19:01 ` [Qemu-devel] [PATCH 1/3] Musicpal qdev conversion : gpio (except I2C part), keyboard and lcd Benoit Canet 2009-08-10 19:01 ` [Qemu-devel] [PATCH 2/3] Extract musicpal.c I2C bitbanging code and make it gpio aware Benoit Canet 2009-08-10 19:01 ` [Qemu-devel] [PATCH 3/3] Make musicpal.c use the generic bitbang I2C device Benoit Canet 2009-08-10 19:47 ` Filip Navara
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).