From patchwork Fri Aug 14 20:23:15 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benoit Canet X-Patchwork-Id: 31436 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by bilbo.ozlabs.org (Postfix) with ESMTPS id 7C507B7B3E for ; Sat, 15 Aug 2009 06:30:51 +1000 (EST) Received: from localhost ([127.0.0.1]:33997 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Mc3QE-0000AJ-S5 for incoming@patchwork.ozlabs.org; Fri, 14 Aug 2009 16:30:46 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Mc3JH-0006tC-63 for qemu-devel@nongnu.org; Fri, 14 Aug 2009 16:23:35 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Mc3JC-0006qw-Cg for qemu-devel@nongnu.org; Fri, 14 Aug 2009 16:23:34 -0400 Received: from [199.232.76.173] (port=36909 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Mc3JB-0006qr-Ti for qemu-devel@nongnu.org; Fri, 14 Aug 2009 16:23:29 -0400 Received: from mail-ew0-f210.google.com ([209.85.219.210]:50862) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Mc3JB-0007yO-CZ for qemu-devel@nongnu.org; Fri, 14 Aug 2009 16:23:29 -0400 Received: by mail-ew0-f210.google.com with SMTP id 6so1941639ewy.34 for ; Fri, 14 Aug 2009 13:23:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer:in-reply-to:references; bh=XegQIvLrSFnKwgTmMYhH5S6sIhpm65xdqifRJaI1dWQ=; b=DJg29bEe/q4Fg2Je/nl1ZAoJAL4bD1LNN8SwFkM2OQ7d/PRPDeC7ZUVgLIS4OEOf70 vhxJBbECP5QWub70TYPIjwcLCmml7QwJtrOGMVa/MdOgAtlZdGTETNP4w7HBy9r1Lu6A y7L5PmxCTKVRIyTnyDSBClZA3m/vvFnNyAA3Q= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=seZVDzAMhp+MwCL0t7w4W6lDNs0KflNVo6UotMFQPvYiHB9mWu96jS8csC1bBrBEMb B9/CnLfV75siWi2LEO78e9KHMt7sRZ8dJRVeXW+X5Scjm0Kl6yq+8LPuikG91+E6gh+R 2SfBw98JQF1xelX66+3+7Kz8Y5BP4NAq+t0lc= Received: by 10.210.38.5 with SMTP id l5mr1293405ebl.64.1250281409100; Fri, 14 Aug 2009 13:23:29 -0700 (PDT) Received: from localhost.localdomain (AMontsouris-157-1-68-201.w90-46.abo.wanadoo.fr [90.46.59.201]) by mx.google.com with ESMTPS id 10sm1145045eyd.35.2009.08.14.13.23.27 (version=SSLv3 cipher=RC4-MD5); Fri, 14 Aug 2009 13:23:28 -0700 (PDT) From: Benoit Canet To: qemu-devel@nongnu.org Date: Fri, 14 Aug 2009 22:23:15 +0200 Message-Id: <1250281397-7660-5-git-send-email-benoit.canet@gmail.com> X-Mailer: git-send-email 1.6.0.4 In-Reply-To: <1250281397-7660-4-git-send-email-benoit.canet@gmail.com> References: <1250281397-7660-1-git-send-email-benoit.canet@gmail.com> <1250281397-7660-2-git-send-email-benoit.canet@gmail.com> <1250281397-7660-3-git-send-email-benoit.canet@gmail.com> <1250281397-7660-4-git-send-email-benoit.canet@gmail.com> X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: Benoit Canet Subject: [Qemu-devel] [PATCH 4/9] Make musicpal.c use the I2C device and the Marvell 88w8618 audio device X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Benoit Canet --- hw/musicpal.c | 427 ++++++--------------------------------------------------- 1 files changed, 40 insertions(+), 387 deletions(-) diff --git a/hw/musicpal.c b/hw/musicpal.c index 067c228..0b00ffc 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -17,7 +17,6 @@ #include "block.h" #include "flash.h" #include "console.h" -#include "audio/audio.h" #include "i2c.h" #define MP_MISC_BASE 0x80002000 @@ -39,7 +38,6 @@ #define MP_FLASHCFG_SIZE 0x00001000 #define MP_AUDIO_BASE 0x90007000 -#define MP_AUDIO_SIZE 0x00001000 #define MP_PIC_BASE 0x90008000 #define MP_PIC_SIZE 0x00001000 @@ -70,385 +68,9 @@ 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 -#define MP_AUDIO_IRQ_STATUS 0x20 -#define MP_AUDIO_IRQ_ENABLE 0x24 -#define MP_AUDIO_TX_START_LO 0x28 -#define MP_AUDIO_TX_THRESHOLD 0x2C -#define MP_AUDIO_TX_STATUS 0x38 -#define MP_AUDIO_TX_START_HI 0x40 - -/* Status register and IRQ enable bits */ -#define MP_AUDIO_TX_HALF (1 << 6) -#define MP_AUDIO_TX_FULL (1 << 7) - -/* Playback mode bits */ -#define MP_AUDIO_16BIT_SAMPLE (1 << 0) -#define MP_AUDIO_PLAYBACK_EN (1 << 7) -#define MP_AUDIO_CLOCK_24MHZ (1 << 9) -#define MP_AUDIO_MONO (1 << 14) - /* Wolfson 8750 I2C address */ #define MP_WM_ADDR 0x34 -static const char audio_name[] = "mv88w8618"; - -typedef struct musicpal_audio_state { - qemu_irq irq; - uint32_t playback_mode; - uint32_t status; - uint32_t irq_enable; - unsigned long phys_buf; - uint32_t target_buffer; - unsigned int threshold; - unsigned int play_pos; - unsigned int last_free; - uint32_t clock_div; - DeviceState *wm; -} musicpal_audio_state; - -static void audio_callback(void *opaque, int free_out, int free_in) -{ - musicpal_audio_state *s = opaque; - int16_t *codec_buffer; - int8_t buf[4096]; - int8_t *mem_buffer; - int pos, block_size; - - if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) - return; - - if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) - free_out <<= 1; - - if (!(s->playback_mode & MP_AUDIO_MONO)) - free_out <<= 1; - - block_size = s->threshold/2; - if (free_out - s->last_free < block_size) - return; - - if (block_size > 4096) - return; - - cpu_physical_memory_read(s->target_buffer + s->play_pos, (void *)buf, - block_size); - mem_buffer = buf; - if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) { - if (s->playback_mode & MP_AUDIO_MONO) { - codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1); - for (pos = 0; pos < block_size; pos += 2) { - *codec_buffer++ = *(int16_t *)mem_buffer; - *codec_buffer++ = *(int16_t *)mem_buffer; - mem_buffer += 2; - } - } else - memcpy(wm8750_dac_buffer(s->wm, block_size >> 2), - (uint32_t *)mem_buffer, block_size); - } else { - if (s->playback_mode & MP_AUDIO_MONO) { - codec_buffer = wm8750_dac_buffer(s->wm, block_size); - for (pos = 0; pos < block_size; pos++) { - *codec_buffer++ = cpu_to_le16(256 * *mem_buffer); - *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); - } - } else { - codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1); - for (pos = 0; pos < block_size; pos += 2) { - *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); - *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); - } - } - } - wm8750_dac_commit(s->wm); - - s->last_free = free_out - block_size; - - if (s->play_pos == 0) { - s->status |= MP_AUDIO_TX_HALF; - s->play_pos = block_size; - } else { - s->status |= MP_AUDIO_TX_FULL; - s->play_pos = 0; - } - - if (s->status & s->irq_enable) - qemu_irq_raise(s->irq); -} - -static void musicpal_audio_clock_update(musicpal_audio_state *s) -{ - int rate; - - if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) - rate = 24576000 / 64; /* 24.576MHz */ - else - rate = 11289600 / 64; /* 11.2896MHz */ - - rate /= ((s->clock_div >> 8) & 0xff) + 1; - - wm8750_set_bclk_in(s->wm, rate); -} - -static uint32_t musicpal_audio_read(void *opaque, target_phys_addr_t offset) -{ - musicpal_audio_state *s = opaque; - - switch (offset) { - case MP_AUDIO_PLAYBACK_MODE: - return s->playback_mode; - - case MP_AUDIO_CLOCK_DIV: - return s->clock_div; - - case MP_AUDIO_IRQ_STATUS: - return s->status; - - case MP_AUDIO_IRQ_ENABLE: - return s->irq_enable; - - case MP_AUDIO_TX_STATUS: - return s->play_pos >> 2; - - default: - return 0; - } -} - -static void musicpal_audio_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - musicpal_audio_state *s = opaque; - - switch (offset) { - case MP_AUDIO_PLAYBACK_MODE: - if (value & MP_AUDIO_PLAYBACK_EN && - !(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) { - s->status = 0; - s->last_free = 0; - s->play_pos = 0; - } - s->playback_mode = value; - musicpal_audio_clock_update(s); - break; - - case MP_AUDIO_CLOCK_DIV: - s->clock_div = value; - s->last_free = 0; - s->play_pos = 0; - musicpal_audio_clock_update(s); - break; - - case MP_AUDIO_IRQ_STATUS: - s->status &= ~value; - break; - - case MP_AUDIO_IRQ_ENABLE: - s->irq_enable = value; - if (s->status & s->irq_enable) - qemu_irq_raise(s->irq); - break; - - case MP_AUDIO_TX_START_LO: - s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF); - s->target_buffer = s->phys_buf; - s->play_pos = 0; - s->last_free = 0; - break; - - case MP_AUDIO_TX_THRESHOLD: - s->threshold = (value + 1) * 4; - break; - - case MP_AUDIO_TX_START_HI: - s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16); - s->target_buffer = s->phys_buf; - s->play_pos = 0; - s->last_free = 0; - break; - } -} - -static void musicpal_audio_reset(void *opaque) -{ - musicpal_audio_state *s = opaque; - - s->playback_mode = 0; - s->status = 0; - s->irq_enable = 0; -} - -static CPUReadMemoryFunc *musicpal_audio_readfn[] = { - musicpal_audio_read, - musicpal_audio_read, - musicpal_audio_read -}; - -static CPUWriteMemoryFunc *musicpal_audio_writefn[] = { - musicpal_audio_write, - musicpal_audio_write, - musicpal_audio_write -}; - -static i2c_interface *musicpal_audio_init(qemu_irq irq) -{ - musicpal_audio_state *s; - i2c_interface *i2c; - 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; - - s->wm = i2c_create_slave(i2c->bus, "wm8750", MP_WM_ADDR); - wm8750_data_req_set(s->wm, 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); - - 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 */ - /* Ethernet register offsets */ #define MP_ETH_SMIR 0x010 #define MP_ETH_PCXR 0x408 @@ -1327,10 +949,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 +1023,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 +1063,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 +1095,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 +1117,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 +1136,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 +1276,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 +1352,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, "mv88w8618_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;