Commit 7e7c5e4c1ba5c9b7efcf1b0c1e34ea150c286e58

Authored by balrog
1 parent a5d7eb65

Nokia N800 machine support (ARM).

Also add various peripherals: two miscellaneous Nokia CBUS chips,
EPSON S1D13745 LCD/TV remote-framebuffer controller,
TWL92230 - standard OMAP2 power management companion chip on i2c.
Generic OneNAND flash memory,
TMP105 temperature sensor on i2c.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4215 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile
... ... @@ -51,7 +51,8 @@ OBJS+=block.o
51 51  
52 52 OBJS+=irq.o
53 53 OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
54   -OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o
  54 +OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
  55 +OBJS+=tmp105.o
55 56 OBJS+=scsi-disk.o cdrom.o
56 57 OBJS+=scsi-generic.o
57 58 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o
... ...
Makefile.target
... ... @@ -612,6 +612,7 @@ OBJS+= spitz.o ide.o serial.o nand.o ecc.o
612 612 OBJS+= omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
613 613 OBJS+= omap2.o omap_dss.o
614 614 OBJS+= palm.o tsc210x.o
  615 +OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o
615 616 OBJS+= mst_fpga.o mainstone.o
616 617 CPPFLAGS += -DHAS_AUDIO
617 618 endif
... ...
hw/blizzard.c 0 → 100644
  1 +/*
  2 + * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
  3 + *
  4 + * Copyright (C) 2008 Nokia Corporation
  5 + * Written by Andrzej Zaborowski <andrew@openedhand.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 or
  10 + * (at your option) version 3 of the License.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#include "qemu-common.h"
  24 +#include "sysemu.h"
  25 +#include "console.h"
  26 +#include "devices.h"
  27 +#include "vga_int.h"
  28 +#include "pixel_ops.h"
  29 +
  30 +typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
  31 +
  32 +struct blizzard_s {
  33 + uint8_t reg;
  34 + uint32_t addr;
  35 + int swallow;
  36 +
  37 + int pll;
  38 + int pll_range;
  39 + int pll_ctrl;
  40 + uint8_t pll_mode;
  41 + uint8_t clksel;
  42 + int memenable;
  43 + int memrefresh;
  44 + uint8_t timing[3];
  45 + int priority;
  46 +
  47 + uint8_t lcd_config;
  48 + int x;
  49 + int y;
  50 + int skipx;
  51 + int skipy;
  52 + uint8_t hndp;
  53 + uint8_t vndp;
  54 + uint8_t hsync;
  55 + uint8_t vsync;
  56 + uint8_t pclk;
  57 + uint8_t u;
  58 + uint8_t v;
  59 + uint8_t yrc[2];
  60 + int ix[2];
  61 + int iy[2];
  62 + int ox[2];
  63 + int oy[2];
  64 +
  65 + int enable;
  66 + int blank;
  67 + int bpp;
  68 + int invalidate;
  69 + int mx[2];
  70 + int my[2];
  71 + uint8_t mode;
  72 + uint8_t effect;
  73 + uint8_t iformat;
  74 + uint8_t source;
  75 + DisplayState *state;
  76 + blizzard_fn_t *line_fn_tab[2];
  77 + void *fb;
  78 +
  79 + uint8_t hssi_config[3];
  80 + uint8_t tv_config;
  81 + uint8_t tv_timing[4];
  82 + uint8_t vbi;
  83 + uint8_t tv_x;
  84 + uint8_t tv_y;
  85 + uint8_t tv_test;
  86 + uint8_t tv_filter_config;
  87 + uint8_t tv_filter_idx;
  88 + uint8_t tv_filter_coeff[0x20];
  89 + uint8_t border_r;
  90 + uint8_t border_g;
  91 + uint8_t border_b;
  92 + uint8_t gamma_config;
  93 + uint8_t gamma_idx;
  94 + uint8_t gamma_lut[0x100];
  95 + uint8_t matrix_ena;
  96 + uint8_t matrix_coeff[0x12];
  97 + uint8_t matrix_r;
  98 + uint8_t matrix_g;
  99 + uint8_t matrix_b;
  100 + uint8_t pm;
  101 + uint8_t status;
  102 + uint8_t rgbgpio_dir;
  103 + uint8_t rgbgpio;
  104 + uint8_t gpio_dir;
  105 + uint8_t gpio;
  106 + uint8_t gpio_edge[2];
  107 + uint8_t gpio_irq;
  108 + uint8_t gpio_pdown;
  109 +
  110 + struct {
  111 + int x;
  112 + int y;
  113 + int dx;
  114 + int dy;
  115 + int len;
  116 + int buflen;
  117 + void *buf;
  118 + void *data;
  119 + uint16_t *ptr;
  120 + int angle;
  121 + int pitch;
  122 + blizzard_fn_t line_fn;
  123 + } data;
  124 +};
  125 +
  126 +/* Bytes(!) per pixel */
  127 +static const int blizzard_iformat_bpp[0x10] = {
  128 + 0,
  129 + 2, /* RGB 5:6:5*/
  130 + 3, /* RGB 6:6:6 mode 1 */
  131 + 3, /* RGB 8:8:8 mode 1 */
  132 + 0, 0,
  133 + 4, /* RGB 6:6:6 mode 2 */
  134 + 4, /* RGB 8:8:8 mode 2 */
  135 + 0, /* YUV 4:2:2 */
  136 + 0, /* YUV 4:2:0 */
  137 + 0, 0, 0, 0, 0, 0,
  138 +};
  139 +
  140 +static inline void blizzard_rgb2yuv(int r, int g, int b,
  141 + int *y, int *u, int *v)
  142 +{
  143 + *y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13);
  144 + *u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13);
  145 + *v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13);
  146 +}
  147 +
  148 +static void blizzard_window(struct blizzard_s *s)
  149 +{
  150 + uint8_t *src, *dst;
  151 + int bypp[2];
  152 + int bypl[3];
  153 + int y;
  154 + blizzard_fn_t fn = s->data.line_fn;
  155 +
  156 + if (!fn)
  157 + return;
  158 + if (s->mx[0] > s->data.x)
  159 + s->mx[0] = s->data.x;
  160 + if (s->my[0] > s->data.y)
  161 + s->my[0] = s->data.y;
  162 + if (s->mx[1] < s->data.x + s->data.dx)
  163 + s->mx[1] = s->data.x + s->data.dx;
  164 + if (s->my[1] < s->data.y + s->data.dy)
  165 + s->my[1] = s->data.y + s->data.dy;
  166 +
  167 + bypp[0] = s->bpp;
  168 + bypp[1] = (s->state->depth + 7) >> 3;
  169 + bypl[0] = bypp[0] * s->data.pitch;
  170 + bypl[1] = bypp[1] * s->x;
  171 + bypl[2] = bypp[0] * s->data.dx;
  172 +
  173 + src = s->data.data;
  174 + dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
  175 + for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
  176 + fn(dst, src, bypl[2]);
  177 +}
  178 +
  179 +static int blizzard_transfer_setup(struct blizzard_s *s)
  180 +{
  181 + if (s->source > 3 || !s->bpp ||
  182 + s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
  183 + return 0;
  184 +
  185 + s->data.angle = s->effect & 3;
  186 + s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
  187 + s->data.x = s->ix[0];
  188 + s->data.y = s->iy[0];
  189 + s->data.dx = s->ix[1] - s->ix[0] + 1;
  190 + s->data.dy = s->iy[1] - s->iy[0] + 1;
  191 + s->data.len = s->bpp * s->data.dx * s->data.dy;
  192 + s->data.pitch = s->data.dx;
  193 + if (s->data.len > s->data.buflen) {
  194 + s->data.buf = realloc(s->data.buf, s->data.len);
  195 + s->data.buflen = s->data.len;
  196 + }
  197 + s->data.ptr = s->data.buf;
  198 + s->data.data = s->data.buf;
  199 + s->data.len /= 2;
  200 + return 1;
  201 +}
  202 +
  203 +static void blizzard_reset(struct blizzard_s *s)
  204 +{
  205 + s->reg = 0;
  206 + s->swallow = 0;
  207 +
  208 + s->pll = 9;
  209 + s->pll_range = 1;
  210 + s->pll_ctrl = 0x14;
  211 + s->pll_mode = 0x32;
  212 + s->clksel = 0x00;
  213 + s->memenable = 0;
  214 + s->memrefresh = 0x25c;
  215 + s->timing[0] = 0x3f;
  216 + s->timing[1] = 0x13;
  217 + s->timing[2] = 0x21;
  218 + s->priority = 0;
  219 +
  220 + s->lcd_config = 0x74;
  221 + s->x = 8;
  222 + s->y = 1;
  223 + s->skipx = 0;
  224 + s->skipy = 0;
  225 + s->hndp = 3;
  226 + s->vndp = 2;
  227 + s->hsync = 1;
  228 + s->vsync = 1;
  229 + s->pclk = 0x80;
  230 +
  231 + s->ix[0] = 0;
  232 + s->ix[1] = 0;
  233 + s->iy[0] = 0;
  234 + s->iy[1] = 0;
  235 + s->ox[0] = 0;
  236 + s->ox[1] = 0;
  237 + s->oy[0] = 0;
  238 + s->oy[1] = 0;
  239 +
  240 + s->yrc[0] = 0x00;
  241 + s->yrc[1] = 0x30;
  242 + s->u = 0;
  243 + s->v = 0;
  244 +
  245 + s->iformat = 3;
  246 + s->source = 0;
  247 + s->bpp = blizzard_iformat_bpp[s->iformat];
  248 +
  249 + s->hssi_config[0] = 0x00;
  250 + s->hssi_config[1] = 0x00;
  251 + s->hssi_config[2] = 0x01;
  252 + s->tv_config = 0x00;
  253 + s->tv_timing[0] = 0x00;
  254 + s->tv_timing[1] = 0x00;
  255 + s->tv_timing[2] = 0x00;
  256 + s->tv_timing[3] = 0x00;
  257 + s->vbi = 0x10;
  258 + s->tv_x = 0x14;
  259 + s->tv_y = 0x03;
  260 + s->tv_test = 0x00;
  261 + s->tv_filter_config = 0x80;
  262 + s->tv_filter_idx = 0x00;
  263 + s->border_r = 0x10;
  264 + s->border_g = 0x80;
  265 + s->border_b = 0x80;
  266 + s->gamma_config = 0x00;
  267 + s->gamma_idx = 0x00;
  268 + s->matrix_ena = 0x00;
  269 + memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
  270 + s->matrix_r = 0x00;
  271 + s->matrix_g = 0x00;
  272 + s->matrix_b = 0x00;
  273 + s->pm = 0x02;
  274 + s->status = 0x00;
  275 + s->rgbgpio_dir = 0x00;
  276 + s->gpio_dir = 0x00;
  277 + s->gpio_edge[0] = 0x00;
  278 + s->gpio_edge[1] = 0x00;
  279 + s->gpio_irq = 0x00;
  280 + s->gpio_pdown = 0xff;
  281 +}
  282 +
  283 +static inline void blizzard_invalidate_display(void *opaque) {
  284 + struct blizzard_s *s = (struct blizzard_s *) opaque;
  285 +
  286 + s->invalidate = 1;
  287 +}
  288 +
  289 +static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
  290 +{
  291 + struct blizzard_s *s = (struct blizzard_s *) opaque;
  292 +
  293 + switch (reg) {
  294 + case 0x00: /* Revision Code */
  295 + return 0xa5;
  296 +
  297 + case 0x02: /* Configuration Readback */
  298 + return 0x83; /* Macrovision OK, CNF[2:0] = 3 */
  299 +
  300 + case 0x04: /* PLL M-Divider */
  301 + return (s->pll - 1) | (1 << 7);
  302 + case 0x06: /* PLL Lock Range Control */
  303 + return s->pll_range;
  304 + case 0x08: /* PLL Lock Synthesis Control 0 */
  305 + return s->pll_ctrl & 0xff;
  306 + case 0x0a: /* PLL Lock Synthesis Control 1 */
  307 + return s->pll_ctrl >> 8;
  308 + case 0x0c: /* PLL Mode Control 0 */
  309 + return s->pll_mode;
  310 +
  311 + case 0x0e: /* Clock-Source Select */
  312 + return s->clksel;
  313 +
  314 + case 0x10: /* Memory Controller Activate */
  315 + case 0x14: /* Memory Controller Bank 0 Status Flag */
  316 + return s->memenable;
  317 +
  318 + case 0x18: /* Auto-Refresh Interval Setting 0 */
  319 + return s->memrefresh & 0xff;
  320 + case 0x1a: /* Auto-Refresh Interval Setting 1 */
  321 + return s->memrefresh >> 8;
  322 +
  323 + case 0x1c: /* Power-On Sequence Timing Control */
  324 + return s->timing[0];
  325 + case 0x1e: /* Timing Control 0 */
  326 + return s->timing[1];
  327 + case 0x20: /* Timing Control 1 */
  328 + return s->timing[2];
  329 +
  330 + case 0x24: /* Arbitration Priority Control */
  331 + return s->priority;
  332 +
  333 + case 0x28: /* LCD Panel Configuration */
  334 + return s->lcd_config;
  335 +
  336 + case 0x2a: /* LCD Horizontal Display Width */
  337 + return s->x >> 3;
  338 + case 0x2c: /* LCD Horizontal Non-display Period */
  339 + return s->hndp;
  340 + case 0x2e: /* LCD Vertical Display Height 0 */
  341 + return s->y & 0xff;
  342 + case 0x30: /* LCD Vertical Display Height 1 */
  343 + return s->y >> 8;
  344 + case 0x32: /* LCD Vertical Non-display Period */
  345 + return s->vndp;
  346 + case 0x34: /* LCD HS Pulse-width */
  347 + return s->hsync;
  348 + case 0x36: /* LCd HS Pulse Start Position */
  349 + return s->skipx >> 3;
  350 + case 0x38: /* LCD VS Pulse-width */
  351 + return s->vsync;
  352 + case 0x3a: /* LCD VS Pulse Start Position */
  353 + return s->skipy;
  354 +
  355 + case 0x3c: /* PCLK Polarity */
  356 + return s->pclk;
  357 +
  358 + case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
  359 + return s->hssi_config[0];
  360 + case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
  361 + return s->hssi_config[1];
  362 + case 0x42: /* High-speed Serial Interface Tx Mode */
  363 + return s->hssi_config[2];
  364 + case 0x44: /* TV Display Configuration */
  365 + return s->tv_config;
  366 + case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */
  367 + return s->tv_timing[(reg - 0x46) >> 1];
  368 + case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
  369 + return s->vbi;
  370 + case 0x50: /* TV Horizontal Start Position */
  371 + return s->tv_x;
  372 + case 0x52: /* TV Vertical Start Position */
  373 + return s->tv_y;
  374 + case 0x54: /* TV Test Pattern Setting */
  375 + return s->tv_test;
  376 + case 0x56: /* TV Filter Setting */
  377 + return s->tv_filter_config;
  378 + case 0x58: /* TV Filter Coefficient Index */
  379 + return s->tv_filter_idx;
  380 + case 0x5a: /* TV Filter Coefficient Data */
  381 + if (s->tv_filter_idx < 0x20)
  382 + return s->tv_filter_coeff[s->tv_filter_idx ++];
  383 + return 0;
  384 +
  385 + case 0x60: /* Input YUV/RGB Translate Mode 0 */
  386 + return s->yrc[0];
  387 + case 0x62: /* Input YUV/RGB Translate Mode 1 */
  388 + return s->yrc[1];
  389 + case 0x64: /* U Data Fix */
  390 + return s->u;
  391 + case 0x66: /* V Data Fix */
  392 + return s->v;
  393 +
  394 + case 0x68: /* Display Mode */
  395 + return s->mode;
  396 +
  397 + case 0x6a: /* Special Effects */
  398 + return s->effect;
  399 +
  400 + case 0x6c: /* Input Window X Start Position 0 */
  401 + return s->ix[0] & 0xff;
  402 + case 0x6e: /* Input Window X Start Position 1 */
  403 + return s->ix[0] >> 3;
  404 + case 0x70: /* Input Window Y Start Position 0 */
  405 + return s->ix[0] & 0xff;
  406 + case 0x72: /* Input Window Y Start Position 1 */
  407 + return s->ix[0] >> 3;
  408 + case 0x74: /* Input Window X End Position 0 */
  409 + return s->ix[1] & 0xff;
  410 + case 0x76: /* Input Window X End Position 1 */
  411 + return s->ix[1] >> 3;
  412 + case 0x78: /* Input Window Y End Position 0 */
  413 + return s->ix[1] & 0xff;
  414 + case 0x7a: /* Input Window Y End Position 1 */
  415 + return s->ix[1] >> 3;
  416 + case 0x7c: /* Output Window X Start Position 0 */
  417 + return s->ox[0] & 0xff;
  418 + case 0x7e: /* Output Window X Start Position 1 */
  419 + return s->ox[0] >> 3;
  420 + case 0x80: /* Output Window Y Start Position 0 */
  421 + return s->oy[0] & 0xff;
  422 + case 0x82: /* Output Window Y Start Position 1 */
  423 + return s->oy[0] >> 3;
  424 + case 0x84: /* Output Window X End Position 0 */
  425 + return s->ox[1] & 0xff;
  426 + case 0x86: /* Output Window X End Position 1 */
  427 + return s->ox[1] >> 3;
  428 + case 0x88: /* Output Window Y End Position 0 */
  429 + return s->oy[1] & 0xff;
  430 + case 0x8a: /* Output Window Y End Position 1 */
  431 + return s->oy[1] >> 3;
  432 +
  433 + case 0x8c: /* Input Data Format */
  434 + return s->iformat;
  435 + case 0x8e: /* Data Source Select */
  436 + return s->source;
  437 + case 0x90: /* Display Memory Data Port */
  438 + return 0;
  439 +
  440 + case 0xa8: /* Border Color 0 */
  441 + return s->border_r;
  442 + case 0xaa: /* Border Color 1 */
  443 + return s->border_g;
  444 + case 0xac: /* Border Color 2 */
  445 + return s->border_b;
  446 +
  447 + case 0xb4: /* Gamma Correction Enable */
  448 + return s->gamma_config;
  449 + case 0xb6: /* Gamma Correction Table Index */
  450 + return s->gamma_idx;
  451 + case 0xb8: /* Gamma Correction Table Data */
  452 + return s->gamma_lut[s->gamma_idx ++];
  453 +
  454 + case 0xba: /* 3x3 Matrix Enable */
  455 + return s->matrix_ena;
  456 + case 0xbc ... 0xde: /* Coefficient Registers */
  457 + return s->matrix_coeff[(reg - 0xbc) >> 1];
  458 + case 0xe0: /* 3x3 Matrix Red Offset */
  459 + return s->matrix_r;
  460 + case 0xe2: /* 3x3 Matrix Green Offset */
  461 + return s->matrix_g;
  462 + case 0xe4: /* 3x3 Matrix Blue Offset */
  463 + return s->matrix_b;
  464 +
  465 + case 0xe6: /* Power-save */
  466 + return s->pm;
  467 + case 0xe8: /* Non-display Period Control / Status */
  468 + return s->status | (1 << 5);
  469 + case 0xea: /* RGB Interface Control */
  470 + return s->rgbgpio_dir;
  471 + case 0xec: /* RGB Interface Status */
  472 + return s->rgbgpio;
  473 + case 0xee: /* General-purpose IO Pins Configuration */
  474 + return s->gpio_dir;
  475 + case 0xf0: /* General-purpose IO Pins Status / Control */
  476 + return s->gpio;
  477 + case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
  478 + return s->gpio_edge[0];
  479 + case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
  480 + return s->gpio_edge[1];
  481 + case 0xf6: /* GPIO Interrupt Status */
  482 + return s->gpio_irq;
  483 + case 0xf8: /* GPIO Pull-down Control */
  484 + return s->gpio_pdown;
  485 +
  486 + default:
  487 + fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
  488 + return 0;
  489 + }
  490 +}
  491 +
  492 +static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
  493 +{
  494 + struct blizzard_s *s = (struct blizzard_s *) opaque;
  495 +
  496 + switch (reg) {
  497 + case 0x04: /* PLL M-Divider */
  498 + s->pll = (value & 0x3f) + 1;
  499 + break;
  500 + case 0x06: /* PLL Lock Range Control */
  501 + s->pll_range = value & 3;
  502 + break;
  503 + case 0x08: /* PLL Lock Synthesis Control 0 */
  504 + s->pll_ctrl &= 0xf00;
  505 + s->pll_ctrl |= (value << 0) & 0x0ff;
  506 + break;
  507 + case 0x0a: /* PLL Lock Synthesis Control 1 */
  508 + s->pll_ctrl &= 0x0ff;
  509 + s->pll_ctrl |= (value << 8) & 0xf00;
  510 + break;
  511 + case 0x0c: /* PLL Mode Control 0 */
  512 + s->pll_mode = value & 0x77;
  513 + if ((value & 3) == 0 || (value & 3) == 3)
  514 + fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
  515 + __FUNCTION__, value & 3);
  516 + break;
  517 +
  518 + case 0x0e: /* Clock-Source Select */
  519 + s->clksel = value & 0xff;
  520 + break;
  521 +
  522 + case 0x10: /* Memory Controller Activate */
  523 + s->memenable = value & 1;
  524 + break;
  525 + case 0x14: /* Memory Controller Bank 0 Status Flag */
  526 + break;
  527 +
  528 + case 0x18: /* Auto-Refresh Interval Setting 0 */
  529 + s->memrefresh &= 0xf00;
  530 + s->memrefresh |= (value << 0) & 0x0ff;
  531 + break;
  532 + case 0x1a: /* Auto-Refresh Interval Setting 1 */
  533 + s->memrefresh &= 0x0ff;
  534 + s->memrefresh |= (value << 8) & 0xf00;
  535 + break;
  536 +
  537 + case 0x1c: /* Power-On Sequence Timing Control */
  538 + s->timing[0] = value & 0x7f;
  539 + break;
  540 + case 0x1e: /* Timing Control 0 */
  541 + s->timing[1] = value & 0x17;
  542 + break;
  543 + case 0x20: /* Timing Control 1 */
  544 + s->timing[2] = value & 0x35;
  545 + break;
  546 +
  547 + case 0x24: /* Arbitration Priority Control */
  548 + s->priority = value & 1;
  549 + break;
  550 +
  551 + case 0x28: /* LCD Panel Configuration */
  552 + s->lcd_config = value & 0xff;
  553 + if (value & (1 << 7))
  554 + fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__);
  555 + break;
  556 +
  557 + case 0x2a: /* LCD Horizontal Display Width */
  558 + s->x = value << 3;
  559 + break;
  560 + case 0x2c: /* LCD Horizontal Non-display Period */
  561 + s->hndp = value & 0xff;
  562 + break;
  563 + case 0x2e: /* LCD Vertical Display Height 0 */
  564 + s->y &= 0x300;
  565 + s->y |= (value << 0) & 0x0ff;
  566 + break;
  567 + case 0x30: /* LCD Vertical Display Height 1 */
  568 + s->y &= 0x0ff;
  569 + s->y |= (value << 8) & 0x300;
  570 + break;
  571 + case 0x32: /* LCD Vertical Non-display Period */
  572 + s->vndp = value & 0xff;
  573 + break;
  574 + case 0x34: /* LCD HS Pulse-width */
  575 + s->hsync = value & 0xff;
  576 + break;
  577 + case 0x36: /* LCD HS Pulse Start Position */
  578 + s->skipx = value & 0xff;
  579 + break;
  580 + case 0x38: /* LCD VS Pulse-width */
  581 + s->vsync = value & 0xbf;
  582 + break;
  583 + case 0x3a: /* LCD VS Pulse Start Position */
  584 + s->skipy = value & 0xff;
  585 + break;
  586 +
  587 + case 0x3c: /* PCLK Polarity */
  588 + s->pclk = value & 0x82;
  589 + /* Affects calculation of s->hndp, s->hsync and s->skipx. */
  590 + break;
  591 +
  592 + case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
  593 + s->hssi_config[0] = value;
  594 + break;
  595 + case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
  596 + s->hssi_config[1] = value;
  597 + if (((value >> 4) & 3) == 3)
  598 + fprintf(stderr, "%s: Illegal active-data-links value\n",
  599 + __FUNCTION__);
  600 + break;
  601 + case 0x42: /* High-speed Serial Interface Tx Mode */
  602 + s->hssi_config[2] = value & 0xbd;
  603 + break;
  604 +
  605 + case 0x44: /* TV Display Configuration */
  606 + s->tv_config = value & 0xfe;
  607 + break;
  608 + case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */
  609 + s->tv_timing[(reg - 0x46) >> 1] = value;
  610 + break;
  611 + case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
  612 + s->vbi = value;
  613 + break;
  614 + case 0x50: /* TV Horizontal Start Position */
  615 + s->tv_x = value;
  616 + break;
  617 + case 0x52: /* TV Vertical Start Position */
  618 + s->tv_y = value & 0x7f;
  619 + break;
  620 + case 0x54: /* TV Test Pattern Setting */
  621 + s->tv_test = value;
  622 + break;
  623 + case 0x56: /* TV Filter Setting */
  624 + s->tv_filter_config = value & 0xbf;
  625 + break;
  626 + case 0x58: /* TV Filter Coefficient Index */
  627 + s->tv_filter_idx = value & 0x1f;
  628 + break;
  629 + case 0x5a: /* TV Filter Coefficient Data */
  630 + if (s->tv_filter_idx < 0x20)
  631 + s->tv_filter_coeff[s->tv_filter_idx ++] = value;
  632 + break;
  633 +
  634 + case 0x60: /* Input YUV/RGB Translate Mode 0 */
  635 + s->yrc[0] = value & 0xb0;
  636 + break;
  637 + case 0x62: /* Input YUV/RGB Translate Mode 1 */
  638 + s->yrc[1] = value & 0x30;
  639 + break;
  640 + case 0x64: /* U Data Fix */
  641 + s->u = value & 0xff;
  642 + break;
  643 + case 0x66: /* V Data Fix */
  644 + s->v = value & 0xff;
  645 + break;
  646 +
  647 + case 0x68: /* Display Mode */
  648 + if ((s->mode ^ value) & 3)
  649 + s->invalidate = 1;
  650 + s->mode = value & 0xb7;
  651 + s->enable = value & 1;
  652 + s->blank = (value >> 1) & 1;
  653 + if (value & (1 << 4))
  654 + fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__);
  655 + break;
  656 +
  657 + case 0x6a: /* Special Effects */
  658 + s->effect = value & 0xfb;
  659 + break;
  660 +
  661 + case 0x6c: /* Input Window X Start Position 0 */
  662 + s->ix[0] &= 0x300;
  663 + s->ix[0] |= (value << 0) & 0x0ff;
  664 + break;
  665 + case 0x6e: /* Input Window X Start Position 1 */
  666 + s->ix[0] &= 0x0ff;
  667 + s->ix[0] |= (value << 8) & 0x300;
  668 + break;
  669 + case 0x70: /* Input Window Y Start Position 0 */
  670 + s->iy[0] &= 0x300;
  671 + s->iy[0] |= (value << 0) & 0x0ff;
  672 + break;
  673 + case 0x72: /* Input Window Y Start Position 1 */
  674 + s->iy[0] &= 0x0ff;
  675 + s->iy[0] |= (value << 8) & 0x300;
  676 + break;
  677 + case 0x74: /* Input Window X End Position 0 */
  678 + s->ix[1] &= 0x300;
  679 + s->ix[1] |= (value << 0) & 0x0ff;
  680 + break;
  681 + case 0x76: /* Input Window X End Position 1 */
  682 + s->ix[1] &= 0x0ff;
  683 + s->ix[1] |= (value << 8) & 0x300;
  684 + break;
  685 + case 0x78: /* Input Window Y End Position 0 */
  686 + s->iy[1] &= 0x300;
  687 + s->iy[1] |= (value << 0) & 0x0ff;
  688 + break;
  689 + case 0x7a: /* Input Window Y End Position 1 */
  690 + s->iy[1] &= 0x0ff;
  691 + s->iy[1] |= (value << 8) & 0x300;
  692 + break;
  693 + case 0x7c: /* Output Window X Start Position 0 */
  694 + s->ox[0] &= 0x300;
  695 + s->ox[0] |= (value << 0) & 0x0ff;
  696 + break;
  697 + case 0x7e: /* Output Window X Start Position 1 */
  698 + s->ox[0] &= 0x0ff;
  699 + s->ox[0] |= (value << 8) & 0x300;
  700 + break;
  701 + case 0x80: /* Output Window Y Start Position 0 */
  702 + s->oy[0] &= 0x300;
  703 + s->oy[0] |= (value << 0) & 0x0ff;
  704 + break;
  705 + case 0x82: /* Output Window Y Start Position 1 */
  706 + s->oy[0] &= 0x0ff;
  707 + s->oy[0] |= (value << 8) & 0x300;
  708 + break;
  709 + case 0x84: /* Output Window X End Position 0 */
  710 + s->ox[1] &= 0x300;
  711 + s->ox[1] |= (value << 0) & 0x0ff;
  712 + break;
  713 + case 0x86: /* Output Window X End Position 1 */
  714 + s->ox[1] &= 0x0ff;
  715 + s->ox[1] |= (value << 8) & 0x300;
  716 + break;
  717 + case 0x88: /* Output Window Y End Position 0 */
  718 + s->oy[1] &= 0x300;
  719 + s->oy[1] |= (value << 0) & 0x0ff;
  720 + break;
  721 + case 0x8a: /* Output Window Y End Position 1 */
  722 + s->oy[1] &= 0x0ff;
  723 + s->oy[1] |= (value << 8) & 0x300;
  724 + break;
  725 +
  726 + case 0x8c: /* Input Data Format */
  727 + s->iformat = value & 0xf;
  728 + s->bpp = blizzard_iformat_bpp[s->iformat];
  729 + if (!s->bpp)
  730 + fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
  731 + __FUNCTION__, s->iformat);
  732 + break;
  733 + case 0x8e: /* Data Source Select */
  734 + s->source = value & 7;
  735 + /* Currently all windows will be "destructive overlays". */
  736 + if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
  737 + s->iy[0] != s->oy[0] ||
  738 + s->ix[1] != s->ox[1] ||
  739 + s->iy[1] != s->oy[1])) ||
  740 + !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
  741 + (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
  742 + fprintf(stderr, "%s: Illegal input/output window positions\n",
  743 + __FUNCTION__);
  744 +
  745 + blizzard_transfer_setup(s);
  746 + break;
  747 +
  748 + case 0x90: /* Display Memory Data Port */
  749 + if (!s->data.len && !blizzard_transfer_setup(s))
  750 + break;
  751 +
  752 + *s->data.ptr ++ = value;
  753 + if (-- s->data.len == 0)
  754 + blizzard_window(s);
  755 + break;
  756 +
  757 + case 0xa8: /* Border Color 0 */
  758 + s->border_r = value;
  759 + break;
  760 + case 0xaa: /* Border Color 1 */
  761 + s->border_g = value;
  762 + break;
  763 + case 0xac: /* Border Color 2 */
  764 + s->border_b = value;
  765 + break;
  766 +
  767 + case 0xb4: /* Gamma Correction Enable */
  768 + s->gamma_config = value & 0x87;
  769 + break;
  770 + case 0xb6: /* Gamma Correction Table Index */
  771 + s->gamma_idx = value;
  772 + break;
  773 + case 0xb8: /* Gamma Correction Table Data */
  774 + s->gamma_lut[s->gamma_idx ++] = value;
  775 + break;
  776 +
  777 + case 0xba: /* 3x3 Matrix Enable */
  778 + s->matrix_ena = value & 1;
  779 + break;
  780 + case 0xbc ... 0xde: /* Coefficient Registers */
  781 + s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
  782 + break;
  783 + case 0xe0: /* 3x3 Matrix Red Offset */
  784 + s->matrix_r = value;
  785 + break;
  786 + case 0xe2: /* 3x3 Matrix Green Offset */
  787 + s->matrix_g = value;
  788 + break;
  789 + case 0xe4: /* 3x3 Matrix Blue Offset */
  790 + s->matrix_b = value;
  791 + break;
  792 +
  793 + case 0xe6: /* Power-save */
  794 + s->pm = value & 0x83;
  795 + if (value & s->mode & 1)
  796 + fprintf(stderr, "%s: The display must be disabled before entering "
  797 + "Standby Mode\n", __FUNCTION__);
  798 + break;
  799 + case 0xe8: /* Non-display Period Control / Status */
  800 + s->status = value & 0x1b;
  801 + break;
  802 + case 0xea: /* RGB Interface Control */
  803 + s->rgbgpio_dir = value & 0x8f;
  804 + break;
  805 + case 0xec: /* RGB Interface Status */
  806 + s->rgbgpio = value & 0xcf;
  807 + break;
  808 + case 0xee: /* General-purpose IO Pins Configuration */
  809 + s->gpio_dir = value;
  810 + break;
  811 + case 0xf0: /* General-purpose IO Pins Status / Control */
  812 + s->gpio = value;
  813 + break;
  814 + case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
  815 + s->gpio_edge[0] = value;
  816 + break;
  817 + case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
  818 + s->gpio_edge[1] = value;
  819 + break;
  820 + case 0xf6: /* GPIO Interrupt Status */
  821 + s->gpio_irq &= value;
  822 + break;
  823 + case 0xf8: /* GPIO Pull-down Control */
  824 + s->gpio_pdown = value;
  825 + break;
  826 +
  827 + default:
  828 + fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
  829 + break;
  830 + }
  831 +}
  832 +
  833 +uint16_t s1d13745_read(void *opaque, int dc)
  834 +{
  835 + struct blizzard_s *s = (struct blizzard_s *) opaque;
  836 + uint16_t value = blizzard_reg_read(s, s->reg);
  837 +
  838 + if (s->swallow -- > 0)
  839 + return 0;
  840 + if (dc)
  841 + s->reg ++;
  842 +
  843 + return value;
  844 +}
  845 +
  846 +void s1d13745_write(void *opaque, int dc, uint16_t value)
  847 +{
  848 + struct blizzard_s *s = (struct blizzard_s *) opaque;
  849 +
  850 + if (s->swallow -- > 0)
  851 + return;
  852 + if (dc) {
  853 + blizzard_reg_write(s, s->reg, value);
  854 +
  855 + if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
  856 + s->reg += 2;
  857 + } else
  858 + s->reg = value & 0xff;
  859 +}
  860 +
  861 +void s1d13745_write_block(void *opaque, int dc,
  862 + void *buf, size_t len, int pitch)
  863 +{
  864 + struct blizzard_s *s = (struct blizzard_s *) opaque;
  865 +
  866 + while (len > 0) {
  867 + if (s->reg == 0x90 && dc &&
  868 + (s->data.len || blizzard_transfer_setup(s)) &&
  869 + len >= (s->data.len << 1)) {
  870 + len -= s->data.len << 1;
  871 + s->data.len = 0;
  872 + s->data.data = buf;
  873 + if (pitch)
  874 + s->data.pitch = pitch;
  875 + blizzard_window(s);
  876 + s->data.data = s->data.buf;
  877 + continue;
  878 + }
  879 +
  880 + s1d13745_write(opaque, dc, *(uint16_t *) buf);
  881 + len -= 2;
  882 + buf += 2;
  883 + }
  884 +
  885 + return;
  886 +}
  887 +
  888 +static void blizzard_update_display(void *opaque)
  889 +{
  890 + struct blizzard_s *s = (struct blizzard_s *) opaque;
  891 + int y, bypp, bypl, bwidth;
  892 + uint8_t *src, *dst;
  893 +
  894 + if (!s->enable)
  895 + return;
  896 +
  897 + if (s->x != s->state->width || s->y != s->state->height) {
  898 + s->invalidate = 1;
  899 + dpy_resize(s->state, s->x, s->y);
  900 + }
  901 +
  902 + if (s->invalidate) {
  903 + s->invalidate = 0;
  904 +
  905 + if (s->blank) {
  906 + bypp = (s->state->depth + 7) >> 3;
  907 + memset(s->state->data, 0, bypp * s->x * s->y);
  908 + return;
  909 + }
  910 +
  911 + s->mx[0] = 0;
  912 + s->mx[1] = s->x;
  913 + s->my[0] = 0;
  914 + s->my[1] = s->y;
  915 + }
  916 +
  917 + if (s->mx[1] <= s->mx[0])
  918 + return;
  919 +
  920 + bypp = (s->state->depth + 7) >> 3;
  921 + bypl = bypp * s->x;
  922 + bwidth = bypp * (s->mx[1] - s->mx[0]);
  923 + y = s->my[0];
  924 + src = s->fb + bypl * y + bypp * s->mx[0];
  925 + dst = s->state->data + bypl * y + bypp * s->mx[0];
  926 + for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
  927 + memcpy(dst, src, bwidth);
  928 +
  929 + dpy_update(s->state, s->mx[0], s->my[0],
  930 + s->mx[1] - s->mx[0], y - s->my[0]);
  931 +
  932 + s->mx[0] = s->x;
  933 + s->mx[1] = 0;
  934 + s->my[0] = s->y;
  935 + s->my[1] = 0;
  936 +}
  937 +
  938 +static void blizzard_screen_dump(void *opaque, const char *filename) {
  939 + struct blizzard_s *s = (struct blizzard_s *) opaque;
  940 +
  941 + blizzard_update_display(opaque);
  942 + if (s && s->state->data)
  943 + ppm_save(filename, s->state->data, s->x, s->y, s->state->linesize);
  944 +}
  945 +
  946 +#define DEPTH 8
  947 +#include "blizzard_template.h"
  948 +#define DEPTH 15
  949 +#include "blizzard_template.h"
  950 +#define DEPTH 16
  951 +#include "blizzard_template.h"
  952 +#define DEPTH 24
  953 +#include "blizzard_template.h"
  954 +#define DEPTH 32
  955 +#include "blizzard_template.h"
  956 +
  957 +void *s1d13745_init(qemu_irq gpio_int, DisplayState *ds)
  958 +{
  959 + struct blizzard_s *s = (struct blizzard_s *) qemu_mallocz(sizeof(*s));
  960 +
  961 + s->state = ds;
  962 + s->fb = qemu_malloc(0x180000);
  963 +
  964 + switch (s->state->depth) {
  965 + case 0:
  966 + s->line_fn_tab[0] = s->line_fn_tab[1] =
  967 + qemu_mallocz(sizeof(blizzard_fn_t) * 0x10);
  968 + break;
  969 + case 8:
  970 + s->line_fn_tab[0] = blizzard_draw_fn_8;
  971 + s->line_fn_tab[1] = blizzard_draw_fn_r_8;
  972 + break;
  973 + case 15:
  974 + s->line_fn_tab[0] = blizzard_draw_fn_15;
  975 + s->line_fn_tab[1] = blizzard_draw_fn_r_15;
  976 + break;
  977 + case 16:
  978 + s->line_fn_tab[0] = blizzard_draw_fn_16;
  979 + s->line_fn_tab[1] = blizzard_draw_fn_r_16;
  980 + break;
  981 + case 24:
  982 + s->line_fn_tab[0] = blizzard_draw_fn_24;
  983 + s->line_fn_tab[1] = blizzard_draw_fn_r_24;
  984 + break;
  985 + case 32:
  986 + s->line_fn_tab[0] = blizzard_draw_fn_32;
  987 + s->line_fn_tab[1] = blizzard_draw_fn_r_32;
  988 + break;
  989 + default:
  990 + fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
  991 + exit(1);
  992 + }
  993 +
  994 + blizzard_reset(s);
  995 +
  996 + graphic_console_init(s->state, blizzard_update_display,
  997 + blizzard_invalidate_display, blizzard_screen_dump,
  998 + NULL, s);
  999 +
  1000 + return s;
  1001 +}
... ...
hw/blizzard_template.h 0 → 100644
  1 +/*
  2 + * QEMU Epson S1D13744/S1D13745 templates
  3 + *
  4 + * Copyright (C) 2008 Nokia Corporation
  5 + * Written by Andrzej Zaborowski <andrew@openedhand.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 or
  10 + * (at your option) version 3 of the License.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#define SKIP_PIXEL(to) to += deststep
  24 +#if DEPTH == 8
  25 +# define PIXEL_TYPE uint8_t
  26 +# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to)
  27 +# define COPY_PIXEL1(to, from) *to ++ = from
  28 +#elif DEPTH == 15 || DEPTH == 16
  29 +# define PIXEL_TYPE uint16_t
  30 +# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to)
  31 +# define COPY_PIXEL1(to, from) *to ++ = from
  32 +#elif DEPTH == 24
  33 +# define PIXEL_TYPE uint8_t
  34 +# define COPY_PIXEL(to, from) \
  35 + to[0] = from; to[1] = (from) >> 8; to[2] = (from) >> 16; SKIP_PIXEL(to)
  36 +# define COPY_PIXEL1(to, from) \
  37 + *to ++ = from; *to ++ = (from) >> 8; *to ++ = (from) >> 16
  38 +#elif DEPTH == 32
  39 +# define PIXEL_TYPE uint32_t
  40 +# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to)
  41 +# define COPY_PIXEL1(to, from) *to ++ = from
  42 +#else
  43 +# error unknown bit depth
  44 +#endif
  45 +
  46 +#ifdef WORDS_BIGENDIAN
  47 +# define SWAP_WORDS 1
  48 +#endif
  49 +
  50 +static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
  51 + const uint16_t *src, unsigned int width)
  52 +{
  53 +#if !defined(SWAP_WORDS) && DEPTH == 16
  54 + memcpy(dest, src, width << 1);
  55 +#else
  56 + uint16_t data;
  57 + unsigned int r, g, b;
  58 + const uint16_t *end = (void *) src + width;
  59 + while (src < end) {
  60 + data = lduw_raw(src ++);
  61 + b = (data & 0x1f) << 3;
  62 + data >>= 5;
  63 + g = (data & 0x3f) << 2;
  64 + data >>= 6;
  65 + r = (data & 0x1f) << 3;
  66 + data >>= 5;
  67 + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
  68 + }
  69 +#endif
  70 +}
  71 +
  72 +static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest,
  73 + const uint8_t *src, unsigned int width)
  74 +{
  75 + /* TODO: check if SDL 24-bit planes are not in the same format and
  76 + * if so, use memcpy */
  77 + unsigned int r[2], g[2], b[2];
  78 + const uint8_t *end = src + width;
  79 + while (src < end) {
  80 + g[0] = *src ++;
  81 + r[0] = *src ++;
  82 + r[1] = *src ++;
  83 + b[0] = *src ++;
  84 + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0]));
  85 + b[1] = *src ++;
  86 + g[1] = *src ++;
  87 + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1]));
  88 + }
  89 +}
  90 +
  91 +static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest,
  92 + const uint8_t *src, unsigned int width)
  93 +{
  94 + unsigned int r, g, b;
  95 + const uint8_t *end = src + width;
  96 + while (src < end) {
  97 + r = *src ++;
  98 + src ++;
  99 + b = *src ++;
  100 + g = *src ++;
  101 + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
  102 + }
  103 +}
  104 +
  105 +/* No rotation */
  106 +static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = {
  107 + NULL,
  108 + /* RGB 5:6:5*/
  109 + (blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH),
  110 + /* RGB 6:6:6 mode 1 */
  111 + (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
  112 + /* RGB 8:8:8 mode 1 */
  113 + (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
  114 + NULL, NULL,
  115 + /* RGB 6:6:6 mode 2 */
  116 + (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
  117 + /* RGB 8:8:8 mode 2 */
  118 + (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
  119 + /* YUV 4:2:2 */
  120 + NULL,
  121 + /* YUV 4:2:0 */
  122 + NULL,
  123 + NULL, NULL, NULL, NULL, NULL, NULL,
  124 +};
  125 +
  126 +/* 90deg, 180deg and 270deg rotation */
  127 +static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = {
  128 + /* TODO */
  129 + [0 ... 0xf] = NULL,
  130 +};
  131 +
  132 +#undef DEPTH
  133 +#undef SKIP_PIXEL
  134 +#undef COPY_PIXEL
  135 +#undef COPY_PIXEL1
  136 +#undef PIXEL_TYPE
  137 +
  138 +#undef SWAP_WORDS
... ...
hw/boards.h
... ... @@ -81,6 +81,9 @@ extern QEMUMachine terrierpda_machine;
81 81 /* palm.c */
82 82 extern QEMUMachine palmte_machine;
83 83  
  84 +/* nseries.c */
  85 +extern QEMUMachine n800_machine;
  86 +
84 87 /* gumstix.c */
85 88 extern QEMUMachine connex_machine;
86 89 extern QEMUMachine verdex_machine;
... ...
hw/cbus.c 0 → 100644
  1 +/*
  2 + * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
  3 + * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
  4 + * Based on reverse-engineering of a linux driver.
  5 + *
  6 + * Copyright (C) 2008 Nokia Corporation
  7 + * Written by Andrzej Zaborowski <andrew@openedhand.com>
  8 + *
  9 + * This program is free software; you can redistribute it and/or
  10 + * modify it under the terms of the GNU General Public License as
  11 + * published by the Free Software Foundation; either version 2 or
  12 + * (at your option) version 3 of the License.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program; if not, write to the Free Software
  21 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22 + * MA 02111-1307 USA
  23 + */
  24 +
  25 +#include "qemu-common.h"
  26 +#include "irq.h"
  27 +#include "devices.h"
  28 +#include "sysemu.h"
  29 +
  30 +//#define DEBUG
  31 +
  32 +struct cbus_slave_s;
  33 +struct cbus_priv_s {
  34 + struct cbus_s cbus;
  35 +
  36 + int sel;
  37 + int dat;
  38 + int clk;
  39 + int bit;
  40 + int dir;
  41 + uint16_t val;
  42 + qemu_irq dat_out;
  43 +
  44 + int addr;
  45 + int reg;
  46 + int rw;
  47 + enum {
  48 + cbus_address,
  49 + cbus_value,
  50 + } cycle;
  51 +
  52 + struct cbus_slave_s *slave[8];
  53 +};
  54 +
  55 +struct cbus_slave_s {
  56 + void *opaque;
  57 + void (*io)(void *opaque, int rw, int reg, uint16_t *val);
  58 + int addr;
  59 +};
  60 +
  61 +static void cbus_io(struct cbus_priv_s *s)
  62 +{
  63 + if (s->slave[s->addr])
  64 + s->slave[s->addr]->io(s->slave[s->addr]->opaque,
  65 + s->rw, s->reg, &s->val);
  66 + else
  67 + cpu_abort(cpu_single_env, "%s: bad slave address %i\n",
  68 + __FUNCTION__, s->addr);
  69 +}
  70 +
  71 +static void cbus_cycle(struct cbus_priv_s *s)
  72 +{
  73 + switch (s->cycle) {
  74 + case cbus_address:
  75 + s->addr = (s->val >> 6) & 7;
  76 + s->rw = (s->val >> 5) & 1;
  77 + s->reg = (s->val >> 0) & 0x1f;
  78 +
  79 + s->cycle = cbus_value;
  80 + s->bit = 15;
  81 + s->dir = !s->rw;
  82 + s->val = 0;
  83 +
  84 + if (s->rw)
  85 + cbus_io(s);
  86 + break;
  87 +
  88 + case cbus_value:
  89 + if (!s->rw)
  90 + cbus_io(s);
  91 +
  92 + s->cycle = cbus_address;
  93 + s->bit = 8;
  94 + s->dir = 1;
  95 + s->val = 0;
  96 + break;
  97 + }
  98 +}
  99 +
  100 +static void cbus_clk(void *opaque, int line, int level)
  101 +{
  102 + struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
  103 +
  104 + if (!s->sel && level && !s->clk) {
  105 + if (s->dir)
  106 + s->val |= s->dat << (s->bit --);
  107 + else
  108 + qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
  109 +
  110 + if (s->bit < 0)
  111 + cbus_cycle(s);
  112 + }
  113 +
  114 + s->clk = level;
  115 +}
  116 +
  117 +static void cbus_dat(void *opaque, int line, int level)
  118 +{
  119 + struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
  120 +
  121 + s->dat = level;
  122 +}
  123 +
  124 +static void cbus_sel(void *opaque, int line, int level)
  125 +{
  126 + struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
  127 +
  128 + if (!level) {
  129 + s->dir = 1;
  130 + s->bit = 8;
  131 + s->val = 0;
  132 + }
  133 +
  134 + s->sel = level;
  135 +}
  136 +
  137 +struct cbus_s *cbus_init(qemu_irq dat)
  138 +{
  139 + struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s));
  140 +
  141 + s->dat_out = dat;
  142 + s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
  143 + s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
  144 + s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
  145 +
  146 + s->sel = 1;
  147 + s->clk = 0;
  148 + s->dat = 0;
  149 +
  150 + return &s->cbus;
  151 +}
  152 +
  153 +void cbus_attach(struct cbus_s *bus, void *slave_opaque)
  154 +{
  155 + struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque;
  156 + struct cbus_priv_s *s = (struct cbus_priv_s *) bus;
  157 +
  158 + s->slave[slave->addr] = slave;
  159 +}
  160 +
  161 +/* Retu/Vilma */
  162 +struct cbus_retu_s {
  163 + uint16_t irqst;
  164 + uint16_t irqen;
  165 + uint16_t cc[2];
  166 + int channel;
  167 + uint16_t result[16];
  168 + uint16_t sample;
  169 + uint16_t status;
  170 +
  171 + struct {
  172 + uint16_t cal;
  173 + } rtc;
  174 +
  175 + int is_vilma;
  176 + qemu_irq irq;
  177 + struct cbus_slave_s cbus;
  178 +};
  179 +
  180 +static void retu_interrupt_update(struct cbus_retu_s *s)
  181 +{
  182 + qemu_set_irq(s->irq, s->irqst & ~s->irqen);
  183 +}
  184 +
  185 +#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
  186 +#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */
  187 +#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */
  188 +#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */
  189 +#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */
  190 +#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */
  191 +#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */
  192 +#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */
  193 +#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */
  194 +#define RETU_REG_AFCR 0x0a /* (RW) AFC register */
  195 +#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */
  196 +#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/
  197 +#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */
  198 +#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */
  199 +#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */
  200 +#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */
  201 +#define RETU_REG_TXCR 0x11 /* (RW) TxC register */
  202 +#define RETU_REG_STATUS 0x16 /* (RO) Status register */
  203 +#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */
  204 +#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */
  205 +#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */
  206 +#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */
  207 +#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */
  208 +#define RETU_REG_SGR1 0x1c /* (RW) */
  209 +#define RETU_REG_SCR1 0x1d /* (RW) */
  210 +#define RETU_REG_SGR2 0x1e /* (RW) */
  211 +#define RETU_REG_SCR2 0x1f /* (RW) */
  212 +
  213 +/* Retu Interrupt sources */
  214 +enum {
  215 + retu_int_pwr = 0, /* Power button */
  216 + retu_int_char = 1, /* Charger */
  217 + retu_int_rtcs = 2, /* Seconds */
  218 + retu_int_rtcm = 3, /* Minutes */
  219 + retu_int_rtcd = 4, /* Days */
  220 + retu_int_rtca = 5, /* Alarm */
  221 + retu_int_hook = 6, /* Hook */
  222 + retu_int_head = 7, /* Headset */
  223 + retu_int_adcs = 8, /* ADC sample */
  224 +};
  225 +
  226 +/* Retu ADC channel wiring */
  227 +enum {
  228 + retu_adc_bsi = 1, /* BSI */
  229 + retu_adc_batt_temp = 2, /* Battery temperature */
  230 + retu_adc_chg_volt = 3, /* Charger voltage */
  231 + retu_adc_head_det = 4, /* Headset detection */
  232 + retu_adc_hook_det = 5, /* Hook detection */
  233 + retu_adc_rf_gp = 6, /* RF GP */
  234 + retu_adc_tx_det = 7, /* Wideband Tx detection */
  235 + retu_adc_batt_volt = 8, /* Battery voltage */
  236 + retu_adc_sens = 10, /* Light sensor */
  237 + retu_adc_sens_temp = 11, /* Light sensor temperature */
  238 + retu_adc_bbatt_volt = 12, /* Backup battery voltage */
  239 + retu_adc_self_temp = 13, /* RETU temperature */
  240 +};
  241 +
  242 +static inline uint16_t retu_read(struct cbus_retu_s *s, int reg)
  243 +{
  244 +#ifdef DEBUG
  245 + printf("RETU read at %02x\n", reg);
  246 +#endif
  247 +
  248 + switch (reg) {
  249 + case RETU_REG_ASICR:
  250 + return 0x0215 | (s->is_vilma << 7);
  251 +
  252 + case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
  253 + return s->irqst;
  254 +
  255 + case RETU_REG_IMR:
  256 + return s->irqen;
  257 +
  258 + case RETU_REG_RTCDSR:
  259 + case RETU_REG_RTCHMR:
  260 + case RETU_REG_RTCHMAR:
  261 + /* TODO */
  262 + return 0x0000;
  263 +
  264 + case RETU_REG_RTCCALR:
  265 + return s->rtc.cal;
  266 +
  267 + case RETU_REG_ADCR:
  268 + return (s->channel << 10) | s->result[s->channel];
  269 + case RETU_REG_ADCSCR:
  270 + return s->sample;
  271 +
  272 + case RETU_REG_AFCR:
  273 + case RETU_REG_ANTIFR:
  274 + case RETU_REG_CALIBR:
  275 + /* TODO */
  276 + return 0x0000;
  277 +
  278 + case RETU_REG_CCR1:
  279 + return s->cc[0];
  280 + case RETU_REG_CCR2:
  281 + return s->cc[1];
  282 +
  283 + case RETU_REG_RCTRL_CLR:
  284 + case RETU_REG_RCTRL_SET:
  285 + case RETU_REG_TXCR:
  286 + /* TODO */
  287 + return 0x0000;
  288 +
  289 + case RETU_REG_STATUS:
  290 + return s->status;
  291 +
  292 + case RETU_REG_WATCHDOG:
  293 + case RETU_REG_AUDTXR:
  294 + case RETU_REG_AUDPAR:
  295 + case RETU_REG_AUDRXR1:
  296 + case RETU_REG_AUDRXR2:
  297 + case RETU_REG_SGR1:
  298 + case RETU_REG_SCR1:
  299 + case RETU_REG_SGR2:
  300 + case RETU_REG_SCR2:
  301 + /* TODO */
  302 + return 0x0000;
  303 +
  304 + default:
  305 + cpu_abort(cpu_single_env, "%s: bad register %02x\n",
  306 + __FUNCTION__, reg);
  307 + }
  308 +}
  309 +
  310 +static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val)
  311 +{
  312 +#ifdef DEBUG
  313 + printf("RETU write of %04x at %02x\n", val, reg);
  314 +#endif
  315 +
  316 + switch (reg) {
  317 + case RETU_REG_IDR:
  318 + s->irqst ^= val;
  319 + retu_interrupt_update(s);
  320 + break;
  321 +
  322 + case RETU_REG_IMR:
  323 + s->irqen = val;
  324 + retu_interrupt_update(s);
  325 + break;
  326 +
  327 + case RETU_REG_RTCDSR:
  328 + case RETU_REG_RTCHMAR:
  329 + /* TODO */
  330 + break;
  331 +
  332 + case RETU_REG_RTCCALR:
  333 + s->rtc.cal = val;
  334 + break;
  335 +
  336 + case RETU_REG_ADCR:
  337 + s->channel = (val >> 10) & 0xf;
  338 + s->irqst |= 1 << retu_int_adcs;
  339 + retu_interrupt_update(s);
  340 + break;
  341 + case RETU_REG_ADCSCR:
  342 + s->sample &= ~val;
  343 + break;
  344 +
  345 + case RETU_REG_AFCR:
  346 + case RETU_REG_ANTIFR:
  347 + case RETU_REG_CALIBR:
  348 +
  349 + case RETU_REG_CCR1:
  350 + s->cc[0] = val;
  351 + break;
  352 + case RETU_REG_CCR2:
  353 + s->cc[1] = val;
  354 + break;
  355 +
  356 + case RETU_REG_RCTRL_CLR:
  357 + case RETU_REG_RCTRL_SET:
  358 + /* TODO */
  359 + break;
  360 +
  361 + case RETU_REG_WATCHDOG:
  362 + if (val == 0 && (s->cc[0] & 2))
  363 + qemu_system_shutdown_request();
  364 + break;
  365 +
  366 + case RETU_REG_TXCR:
  367 + case RETU_REG_AUDTXR:
  368 + case RETU_REG_AUDPAR:
  369 + case RETU_REG_AUDRXR1:
  370 + case RETU_REG_AUDRXR2:
  371 + case RETU_REG_SGR1:
  372 + case RETU_REG_SCR1:
  373 + case RETU_REG_SGR2:
  374 + case RETU_REG_SCR2:
  375 + /* TODO */
  376 + break;
  377 +
  378 + default:
  379 + cpu_abort(cpu_single_env, "%s: bad register %02x\n",
  380 + __FUNCTION__, reg);
  381 + }
  382 +}
  383 +
  384 +static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
  385 +{
  386 + struct cbus_retu_s *s = (struct cbus_retu_s *) opaque;
  387 +
  388 + if (rw)
  389 + *val = retu_read(s, reg);
  390 + else
  391 + retu_write(s, reg, *val);
  392 +}
  393 +
  394 +void *retu_init(qemu_irq irq, int vilma)
  395 +{
  396 + struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s));
  397 +
  398 + s->irq = irq;
  399 + s->irqen = 0xffff;
  400 + s->irqst = 0x0000;
  401 + s->status = 0x0020;
  402 + s->is_vilma = !!vilma;
  403 + s->rtc.cal = 0x01;
  404 + s->result[retu_adc_bsi] = 0x3c2;
  405 + s->result[retu_adc_batt_temp] = 0x0fc;
  406 + s->result[retu_adc_chg_volt] = 0x165;
  407 + s->result[retu_adc_head_det] = 123;
  408 + s->result[retu_adc_hook_det] = 1023;
  409 + s->result[retu_adc_rf_gp] = 0x11;
  410 + s->result[retu_adc_tx_det] = 0x11;
  411 + s->result[retu_adc_batt_volt] = 0x250;
  412 + s->result[retu_adc_sens] = 2;
  413 + s->result[retu_adc_sens_temp] = 0x11;
  414 + s->result[retu_adc_bbatt_volt] = 0x3d0;
  415 + s->result[retu_adc_self_temp] = 0x330;
  416 +
  417 + s->cbus.opaque = s;
  418 + s->cbus.io = retu_io;
  419 + s->cbus.addr = 1;
  420 +
  421 + return &s->cbus;
  422 +}
  423 +
  424 +void retu_key_event(void *retu, int state)
  425 +{
  426 + struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
  427 + struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
  428 +
  429 + s->irqst |= 1 << retu_int_pwr;
  430 + retu_interrupt_update(s);
  431 +
  432 + if (state)
  433 + s->status &= ~(1 << 5);
  434 + else
  435 + s->status |= 1 << 5;
  436 +}
  437 +
  438 +void retu_head_event(void *retu, int state)
  439 +{
  440 + struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
  441 + struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
  442 +
  443 + if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
  444 + /* TODO: reissue the interrupt every 100ms or so. */
  445 + s->irqst |= 1 << retu_int_head;
  446 + retu_interrupt_update(s);
  447 + }
  448 +
  449 + if (state)
  450 + s->result[retu_adc_head_det] = 50;
  451 + else
  452 + s->result[retu_adc_head_det] = 123;
  453 +}
  454 +
  455 +void retu_hook_event(void *retu, int state)
  456 +{
  457 + struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
  458 + struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
  459 +
  460 + if ((s->cc[0] & 0x500) == 0x500) {
  461 + /* TODO: reissue the interrupt every 100ms or so. */
  462 + s->irqst |= 1 << retu_int_hook;
  463 + retu_interrupt_update(s);
  464 + }
  465 +
  466 + if (state)
  467 + s->result[retu_adc_hook_det] = 50;
  468 + else
  469 + s->result[retu_adc_hook_det] = 123;
  470 +}
  471 +
  472 +/* Tahvo/Betty */
  473 +struct cbus_tahvo_s {
  474 + uint16_t irqst;
  475 + uint16_t irqen;
  476 + uint8_t charger;
  477 + uint8_t backlight;
  478 + uint16_t usbr;
  479 + uint16_t power;
  480 +
  481 + int is_betty;
  482 + qemu_irq irq;
  483 + struct cbus_slave_s cbus;
  484 +};
  485 +
  486 +static void tahvo_interrupt_update(struct cbus_tahvo_s *s)
  487 +{
  488 + qemu_set_irq(s->irq, s->irqst & ~s->irqen);
  489 +}
  490 +
  491 +#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
  492 +#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
  493 +#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
  494 +#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
  495 +#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
  496 +#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
  497 +#define TAHVO_REG_USBR 0x06 /* (RW) USB control */
  498 +#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
  499 +#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
  500 +#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
  501 +#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
  502 +#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
  503 +#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
  504 +#define TAHVO_REG_FRR 0x0d /* (RO) FR */
  505 +
  506 +static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg)
  507 +{
  508 +#ifdef DEBUG
  509 + printf("TAHVO read at %02x\n", reg);
  510 +#endif
  511 +
  512 + switch (reg) {
  513 + case TAHVO_REG_ASICR:
  514 + return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
  515 +
  516 + case TAHVO_REG_IDR:
  517 + case TAHVO_REG_IDSR: /* XXX: what does this do? */
  518 + return s->irqst;
  519 +
  520 + case TAHVO_REG_IMR:
  521 + return s->irqen;
  522 +
  523 + case TAHVO_REG_CHAPWMR:
  524 + return s->charger;
  525 +
  526 + case TAHVO_REG_LEDPWMR:
  527 + return s->backlight;
  528 +
  529 + case TAHVO_REG_USBR:
  530 + return s->usbr;
  531 +
  532 + case TAHVO_REG_RCR:
  533 + return s->power;
  534 +
  535 + case TAHVO_REG_CCR1:
  536 + case TAHVO_REG_CCR2:
  537 + case TAHVO_REG_TESTR1:
  538 + case TAHVO_REG_TESTR2:
  539 + case TAHVO_REG_NOPR:
  540 + case TAHVO_REG_FRR:
  541 + return 0x0000;
  542 +
  543 + default:
  544 + cpu_abort(cpu_single_env, "%s: bad register %02x\n",
  545 + __FUNCTION__, reg);
  546 + }
  547 +}
  548 +
  549 +static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val)
  550 +{
  551 +#ifdef DEBUG
  552 + printf("TAHVO write of %04x at %02x\n", val, reg);
  553 +#endif
  554 +
  555 + switch (reg) {
  556 + case TAHVO_REG_IDR:
  557 + s->irqst ^= val;
  558 + tahvo_interrupt_update(s);
  559 + break;
  560 +
  561 + case TAHVO_REG_IMR:
  562 + s->irqen = val;
  563 + tahvo_interrupt_update(s);
  564 + break;
  565 +
  566 + case TAHVO_REG_CHAPWMR:
  567 + s->charger = val;
  568 + break;
  569 +
  570 + case TAHVO_REG_LEDPWMR:
  571 + if (s->backlight != (val & 0x7f)) {
  572 + s->backlight = val & 0x7f;
  573 + printf("%s: LCD backlight now at %i / 127\n",
  574 + __FUNCTION__, s->backlight);
  575 + }
  576 + break;
  577 +
  578 + case TAHVO_REG_USBR:
  579 + s->usbr = val;
  580 + break;
  581 +
  582 + case TAHVO_REG_RCR:
  583 + s->power = val;
  584 + break;
  585 +
  586 + case TAHVO_REG_CCR1:
  587 + case TAHVO_REG_CCR2:
  588 + case TAHVO_REG_TESTR1:
  589 + case TAHVO_REG_TESTR2:
  590 + case TAHVO_REG_NOPR:
  591 + case TAHVO_REG_FRR:
  592 + break;
  593 +
  594 + default:
  595 + cpu_abort(cpu_single_env, "%s: bad register %02x\n",
  596 + __FUNCTION__, reg);
  597 + }
  598 +}
  599 +
  600 +static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
  601 +{
  602 + struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque;
  603 +
  604 + if (rw)
  605 + *val = tahvo_read(s, reg);
  606 + else
  607 + tahvo_write(s, reg, *val);
  608 +}
  609 +
  610 +void *tahvo_init(qemu_irq irq, int betty)
  611 +{
  612 + struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s));
  613 +
  614 + s->irq = irq;
  615 + s->irqen = 0xffff;
  616 + s->irqst = 0x0000;
  617 + s->is_betty = !!betty;
  618 +
  619 + s->cbus.opaque = s;
  620 + s->cbus.io = tahvo_io;
  621 + s->cbus.addr = 2;
  622 +
  623 + return &s->cbus;
  624 +}
... ...
hw/devices.h
... ... @@ -31,4 +31,25 @@ void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down);
31 31 /* stellaris_input.c */
32 32 void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
33 33  
  34 +/* blizzard.c */
  35 +void *s1d13745_init(qemu_irq gpio_int, DisplayState *ds);
  36 +void s1d13745_write(void *opaque, int dc, uint16_t value);
  37 +void s1d13745_write_block(void *opaque, int dc,
  38 + void *buf, size_t len, int pitch);
  39 +uint16_t s1d13745_read(void *opaque, int dc);
  40 +
  41 +/* cbus.c */
  42 +struct cbus_s {
  43 + qemu_irq clk;
  44 + qemu_irq dat;
  45 + qemu_irq sel;
  46 +};
  47 +struct cbus_s *cbus_init(qemu_irq dat_out);
  48 +void cbus_attach(struct cbus_s *bus, void *slave_opaque);
  49 +
  50 +void *retu_init(qemu_irq irq, int vilma);
  51 +void *tahvo_init(qemu_irq irq, int betty);
  52 +
  53 +void retu_key_event(void *retu, int state);
  54 +
34 55 #endif
... ...
hw/flash.h
... ... @@ -34,6 +34,11 @@ uint8_t nand_getio(struct nand_flash_s *s);
34 34 #define NAND_MFR_HYNIX 0xad
35 35 #define NAND_MFR_MICRON 0x2c
36 36  
  37 +/* onenand.c */
  38 +void onenand_base_update(void *opaque, target_phys_addr_t new);
  39 +void onenand_base_unmap(void *opaque);
  40 +void *onenand_init(uint32_t id, int regshift, qemu_irq irq);
  41 +
37 42 /* ecc.c */
38 43 struct ecc_state_s {
39 44 uint8_t cp; /* Column parity */
... ...
hw/i2c.h
... ... @@ -71,4 +71,14 @@ uint32_t wm8750_adc_dat(void *opaque);
71 71 /* ssd0303.c */
72 72 void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address);
73 73  
  74 +/* twl92230.c */
  75 +i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq);
  76 +qemu_irq *twl92230_gpio_in_get(i2c_slave *i2c);
  77 +void twl92230_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler);
  78 +
  79 +/* tmp105.c */
  80 +struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm);
  81 +void tmp105_reset(i2c_slave *i2c);
  82 +void tmp105_set(i2c_slave *i2c, int temp);
  83 +
74 84 #endif
... ...
hw/nseries.c 0 → 100644
  1 +/*
  2 + * Nokia N-series internet tablets.
  3 + *
  4 + * Copyright (C) 2007 Nokia Corporation
  5 + * Written by Andrzej Zaborowski <andrew@openedhand.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 or
  10 + * (at your option) version 3 of the License.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#include "qemu-common.h"
  24 +#include "sysemu.h"
  25 +#include "omap.h"
  26 +#include "arm-misc.h"
  27 +#include "irq.h"
  28 +#include "console.h"
  29 +#include "boards.h"
  30 +#include "i2c.h"
  31 +#include "devices.h"
  32 +#include "flash.h"
  33 +#include "hw.h"
  34 +
  35 +/* Nokia N8x0 support */
  36 +struct n800_s {
  37 + struct omap_mpu_state_s *cpu;
  38 +
  39 + struct rfbi_chip_s blizzard;
  40 + struct uwire_slave_s *ts;
  41 + i2c_bus *i2c;
  42 +
  43 + int keymap[0x80];
  44 +
  45 + void *retu;
  46 + void *tahvo;
  47 +};
  48 +
  49 +/* GPIO pins */
  50 +#define N800_TUSB_ENABLE_GPIO 0
  51 +#define N800_MMC2_WP_GPIO 8
  52 +#define N800_UNKNOWN_GPIO0 9 /* out */
  53 +#define N800_UNKNOWN_GPIO1 10 /* out */
  54 +#define N800_CAM_TURN_GPIO 12
  55 +#define N800_BLIZZARD_POWERDOWN_GPIO 15
  56 +#define N800_MMC1_WP_GPIO 23
  57 +#define N8X0_ONENAND_GPIO 26
  58 +#define N800_UNKNOWN_GPIO2 53 /* out */
  59 +#define N8X0_TUSB_INT_GPIO 58
  60 +#define N800_BT_WKUP_GPIO 61
  61 +#define N800_STI_GPIO 62
  62 +#define N8X0_CBUS_SEL_GPIO 64
  63 +#define N8X0_CBUS_CLK_GPIO 65 /* sure? */
  64 +#define N8X0_CBUS_DAT_GPIO 66
  65 +#define N800_WLAN_IRQ_GPIO 87
  66 +#define N800_BT_RESET_GPIO 92
  67 +#define N800_TEA5761_CS_GPIO 93
  68 +#define N800_UNKNOWN_GPIO 94
  69 +#define N800_CAM_ACT_GPIO 95
  70 +#define N800_MMC_CS_GPIO 96
  71 +#define N800_WLAN_PWR_GPIO 97
  72 +#define N8X0_BT_HOST_WKUP_GPIO 98
  73 +#define N800_UNKNOWN_GPIO3 101 /* out */
  74 +#define N810_KB_LOCK_GPIO 102
  75 +#define N800_TSC_TS_GPIO 103
  76 +#define N810_TSC2005_GPIO 106
  77 +#define N800_HEADPHONE_GPIO 107
  78 +#define N8X0_RETU_GPIO 108
  79 +#define N800_TSC_KP_IRQ_GPIO 109
  80 +#define N810_KEYBOARD_GPIO 109
  81 +#define N800_BAT_COVER_GPIO 110
  82 +#define N810_SLIDE_GPIO 110
  83 +#define N8X0_TAHVO_GPIO 111
  84 +#define N800_UNKNOWN_GPIO4 112 /* out */
  85 +#define N810_TSC_RESET_GPIO 118
  86 +#define N800_TSC_RESET_GPIO 119 /* ? */
  87 +#define N8X0_TMP105_GPIO 125
  88 +
  89 +/* Config */
  90 +#define XLDR_LL_UART 1
  91 +
  92 +/* Addresses on the I2C bus */
  93 +#define N8X0_TMP105_ADDR 0x48
  94 +#define N8X0_MENELAUS_ADDR 0x72
  95 +
  96 +/* Chipselects on GPMC NOR interface */
  97 +#define N8X0_ONENAND_CS 0
  98 +#define N8X0_USB_ASYNC_CS 1
  99 +#define N8X0_USB_SYNC_CS 4
  100 +
  101 +static void n800_mmc_cs_cb(void *opaque, int line, int level)
  102 +{
  103 + /* TODO: this seems to actually be connected to the menelaus, to
  104 + * which also both MMC slots connect. */
  105 + omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
  106 +
  107 + printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1);
  108 +}
  109 +
  110 +static void n800_gpio_setup(struct n800_s *s)
  111 +{
  112 + qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1);
  113 + omap2_gpio_out_set(s->cpu->gpif, N800_MMC_CS_GPIO, mmc_cs[0]);
  114 +
  115 + qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N800_BAT_COVER_GPIO)[0]);
  116 +}
  117 +
  118 +static void n8x0_nand_setup(struct n800_s *s)
  119 +{
  120 + /* Either ec40xx or ec48xx are OK for the ID */
  121 + omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
  122 + onenand_base_unmap,
  123 + onenand_init(0xec4800, 1,
  124 + omap2_gpio_in_get(s->cpu->gpif,
  125 + N8X0_ONENAND_GPIO)[0]));
  126 +}
  127 +
  128 +static void n800_i2c_setup(struct n800_s *s)
  129 +{
  130 + qemu_irq tmp_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TMP105_GPIO)[0];
  131 +
  132 + /* Attach the CPU on one end of our I2C bus. */
  133 + s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
  134 +
  135 + /* Attach a menelaus PM chip */
  136 + i2c_set_slave_address(
  137 + twl92230_init(s->i2c,
  138 + s->cpu->irq[0][OMAP_INT_24XX_SYS_NIRQ]),
  139 + N8X0_MENELAUS_ADDR);
  140 +
  141 + /* Attach a TMP105 PM chip (A0 wired to ground) */
  142 + i2c_set_slave_address(tmp105_init(s->i2c, tmp_irq), N8X0_TMP105_ADDR);
  143 +}
  144 +
  145 +/* Touchscreen and keypad controller */
  146 +#define RETU_KEYCODE 61 /* F3 */
  147 +
  148 +static void n800_key_event(void *opaque, int keycode)
  149 +{
  150 + struct n800_s *s = (struct n800_s *) opaque;
  151 + int code = s->keymap[keycode & 0x7f];
  152 +
  153 + if (code == -1) {
  154 + if ((keycode & 0x7f) == RETU_KEYCODE)
  155 + retu_key_event(s->retu, !(keycode & 0x80));
  156 + return;
  157 + }
  158 +
  159 + tsc210x_key_event(s->ts, code, !(keycode & 0x80));
  160 +}
  161 +
  162 +static const int n800_keys[16] = {
  163 + -1,
  164 + 72, /* Up */
  165 + 63, /* Home (F5) */
  166 + -1,
  167 + 75, /* Left */
  168 + 28, /* Enter */
  169 + 77, /* Right */
  170 + -1,
  171 + 1, /* Cycle (ESC) */
  172 + 80, /* Down */
  173 + 62, /* Menu (F4) */
  174 + -1,
  175 + 66, /* Zoom- (F8) */
  176 + 64, /* FS (F6) */
  177 + 65, /* Zoom+ (F7) */
  178 + -1,
  179 +};
  180 +
  181 +static struct mouse_transform_info_s n800_pointercal = {
  182 + .x = 800,
  183 + .y = 480,
  184 + .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
  185 +};
  186 +
  187 +static void n800_tsc_setup(struct n800_s *s)
  188 +{
  189 + int i;
  190 +
  191 + /* XXX: are the three pins inverted inside the chip between the
  192 + * tsc and the cpu (N4111)? */
  193 + qemu_irq penirq = 0; /* NC */
  194 + qemu_irq kbirq = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_KP_IRQ_GPIO)[0];
  195 + qemu_irq dav = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_TS_GPIO)[0];
  196 +
  197 + s->ts = tsc2301_init(penirq, kbirq, dav, 0);
  198 +
  199 + for (i = 0; i < 0x80; i ++)
  200 + s->keymap[i] = -1;
  201 + for (i = 0; i < 0x10; i ++)
  202 + if (n800_keys[i] >= 0)
  203 + s->keymap[n800_keys[i]] = i;
  204 +
  205 + qemu_add_kbd_event_handler(n800_key_event, s);
  206 +
  207 + tsc210x_set_transform(s->ts, &n800_pointercal);
  208 +}
  209 +
  210 +/* LCD MIPI DBI-C controller (URAL) */
  211 +struct mipid_s {
  212 + int resp[4];
  213 + int param[4];
  214 + int p;
  215 + int pm;
  216 + int cmd;
  217 +
  218 + int sleep;
  219 + int booster;
  220 + int te;
  221 + int selfcheck;
  222 + int partial;
  223 + int normal;
  224 + int vscr;
  225 + int invert;
  226 + int onoff;
  227 + int gamma;
  228 + uint32_t id;
  229 +};
  230 +
  231 +static void mipid_reset(struct mipid_s *s)
  232 +{
  233 + if (!s->sleep)
  234 + fprintf(stderr, "%s: Display off\n", __FUNCTION__);
  235 +
  236 + s->pm = 0;
  237 + s->cmd = 0;
  238 +
  239 + s->sleep = 1;
  240 + s->booster = 0;
  241 + s->selfcheck =
  242 + (1 << 7) | /* Register loading OK. */
  243 + (1 << 5) | /* The chip is attached. */
  244 + (1 << 4); /* Display glass still in one piece. */
  245 + s->te = 0;
  246 + s->partial = 0;
  247 + s->normal = 1;
  248 + s->vscr = 0;
  249 + s->invert = 0;
  250 + s->onoff = 1;
  251 + s->gamma = 0;
  252 +}
  253 +
  254 +static uint32_t mipid_txrx(void *opaque, uint32_t cmd)
  255 +{
  256 + struct mipid_s *s = (struct mipid_s *) opaque;
  257 + uint8_t ret;
  258 +
  259 + if (s->p >= sizeof(s->resp) / sizeof(*s->resp))
  260 + ret = 0;
  261 + else
  262 + ret = s->resp[s->p ++];
  263 + if (s->pm --> 0)
  264 + s->param[s->pm] = cmd;
  265 + else
  266 + s->cmd = cmd;
  267 +
  268 + switch (s->cmd) {
  269 + case 0x00: /* NOP */
  270 + break;
  271 +
  272 + case 0x01: /* SWRESET */
  273 + mipid_reset(s);
  274 + break;
  275 +
  276 + case 0x02: /* BSTROFF */
  277 + s->booster = 0;
  278 + break;
  279 + case 0x03: /* BSTRON */
  280 + s->booster = 1;
  281 + break;
  282 +
  283 + case 0x04: /* RDDID */
  284 + s->p = 0;
  285 + s->resp[0] = (s->id >> 16) & 0xff;
  286 + s->resp[1] = (s->id >> 8) & 0xff;
  287 + s->resp[2] = (s->id >> 0) & 0xff;
  288 + break;
  289 +
  290 + case 0x06: /* RD_RED */
  291 + case 0x07: /* RD_GREEN */
  292 + /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so
  293 + * for the bootloader one needs to change this. */
  294 + case 0x08: /* RD_BLUE */
  295 + s->p = 0;
  296 + /* TODO: return first pixel components */
  297 + s->resp[0] = 0x01;
  298 + break;
  299 +
  300 + case 0x09: /* RDDST */
  301 + s->p = 0;
  302 + s->resp[0] = s->booster << 7;
  303 + s->resp[1] = (5 << 4) | (s->partial << 2) |
  304 + (s->sleep << 1) | s->normal;
  305 + s->resp[2] = (s->vscr << 7) | (s->invert << 5) |
  306 + (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2);
  307 + s->resp[3] = s->gamma << 6;
  308 + break;
  309 +
  310 + case 0x0a: /* RDDPM */
  311 + s->p = 0;
  312 + s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) |
  313 + (s->partial << 5) | (s->sleep << 6) | (s->booster << 7);
  314 + break;
  315 + case 0x0b: /* RDDMADCTR */
  316 + s->p = 0;
  317 + s->resp[0] = 0;
  318 + break;
  319 + case 0x0c: /* RDDCOLMOD */
  320 + s->p = 0;
  321 + s->resp[0] = 5; /* 65K colours */
  322 + break;
  323 + case 0x0d: /* RDDIM */
  324 + s->p = 0;
  325 + s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma;
  326 + break;
  327 + case 0x0e: /* RDDSM */
  328 + s->p = 0;
  329 + s->resp[0] = s->te << 7;
  330 + break;
  331 + case 0x0f: /* RDDSDR */
  332 + s->p = 0;
  333 + s->resp[0] = s->selfcheck;
  334 + break;
  335 +
  336 + case 0x10: /* SLPIN */
  337 + s->sleep = 1;
  338 + break;
  339 + case 0x11: /* SLPOUT */
  340 + s->sleep = 0;
  341 + s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */
  342 + break;
  343 +
  344 + case 0x12: /* PTLON */
  345 + s->partial = 1;
  346 + s->normal = 0;
  347 + s->vscr = 0;
  348 + break;
  349 + case 0x13: /* NORON */
  350 + s->partial = 0;
  351 + s->normal = 1;
  352 + s->vscr = 0;
  353 + break;
  354 +
  355 + case 0x20: /* INVOFF */
  356 + s->invert = 0;
  357 + break;
  358 + case 0x21: /* INVON */
  359 + s->invert = 1;
  360 + break;
  361 +
  362 + case 0x22: /* APOFF */
  363 + case 0x23: /* APON */
  364 + goto bad_cmd;
  365 +
  366 + case 0x25: /* WRCNTR */
  367 + if (s->pm < 0)
  368 + s->pm = 1;
  369 + goto bad_cmd;
  370 +
  371 + case 0x26: /* GAMSET */
  372 + if (!s->pm)
  373 + s->gamma = ffs(s->param[0] & 0xf) - 1;
  374 + else if (s->pm < 0)
  375 + s->pm = 1;
  376 + break;
  377 +
  378 + case 0x28: /* DISPOFF */
  379 + s->onoff = 0;
  380 + fprintf(stderr, "%s: Display off\n", __FUNCTION__);
  381 + break;
  382 + case 0x29: /* DISPON */
  383 + s->onoff = 1;
  384 + fprintf(stderr, "%s: Display on\n", __FUNCTION__);
  385 + break;
  386 +
  387 + case 0x2a: /* CASET */
  388 + case 0x2b: /* RASET */
  389 + case 0x2c: /* RAMWR */
  390 + case 0x2d: /* RGBSET */
  391 + case 0x2e: /* RAMRD */
  392 + case 0x30: /* PTLAR */
  393 + case 0x33: /* SCRLAR */
  394 + goto bad_cmd;
  395 +
  396 + case 0x34: /* TEOFF */
  397 + s->te = 0;
  398 + break;
  399 + case 0x35: /* TEON */
  400 + if (!s->pm)
  401 + s->te = 1;
  402 + else if (s->pm < 0)
  403 + s->pm = 1;
  404 + break;
  405 +
  406 + case 0x36: /* MADCTR */
  407 + goto bad_cmd;
  408 +
  409 + case 0x37: /* VSCSAD */
  410 + s->partial = 0;
  411 + s->normal = 0;
  412 + s->vscr = 1;
  413 + break;
  414 +
  415 + case 0x38: /* IDMOFF */
  416 + case 0x39: /* IDMON */
  417 + case 0x3a: /* COLMOD */
  418 + goto bad_cmd;
  419 +
  420 + case 0xb0: /* CLKINT / DISCTL */
  421 + case 0xb1: /* CLKEXT */
  422 + if (s->pm < 0)
  423 + s->pm = 2;
  424 + break;
  425 +
  426 + case 0xb4: /* FRMSEL */
  427 + break;
  428 +
  429 + case 0xb5: /* FRM8SEL */
  430 + case 0xb6: /* TMPRNG / INIESC */
  431 + case 0xb7: /* TMPHIS / NOP2 */
  432 + case 0xb8: /* TMPREAD / MADCTL */
  433 + case 0xba: /* DISTCTR */
  434 + case 0xbb: /* EPVOL */
  435 + goto bad_cmd;
  436 +
  437 + case 0xbd: /* Unknown */
  438 + s->p = 0;
  439 + s->resp[0] = 0;
  440 + s->resp[1] = 1;
  441 + break;
  442 +
  443 + case 0xc2: /* IFMOD */
  444 + if (s->pm < 0)
  445 + s->pm = 2;
  446 + break;
  447 +
  448 + case 0xc6: /* PWRCTL */
  449 + case 0xc7: /* PPWRCTL */
  450 + case 0xd0: /* EPWROUT */
  451 + case 0xd1: /* EPWRIN */
  452 + case 0xd4: /* RDEV */
  453 + case 0xd5: /* RDRR */
  454 + goto bad_cmd;
  455 +
  456 + case 0xda: /* RDID1 */
  457 + s->p = 0;
  458 + s->resp[0] = (s->id >> 16) & 0xff;
  459 + break;
  460 + case 0xdb: /* RDID2 */
  461 + s->p = 0;
  462 + s->resp[0] = (s->id >> 8) & 0xff;
  463 + break;
  464 + case 0xdc: /* RDID3 */
  465 + s->p = 0;
  466 + s->resp[0] = (s->id >> 0) & 0xff;
  467 + break;
  468 +
  469 + default:
  470 + bad_cmd:
  471 + fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd);
  472 + break;
  473 + }
  474 +
  475 + return ret;
  476 +}
  477 +
  478 +static void *mipid_init(void)
  479 +{
  480 + struct mipid_s *s = (struct mipid_s *) qemu_mallocz(sizeof(*s));
  481 +
  482 + s->id = 0x838f03;
  483 + mipid_reset(s);
  484 +
  485 + return s;
  486 +}
  487 +
  488 +static void n800_spi_setup(struct n800_s *s)
  489 +{
  490 + void *tsc2301 = s->ts->opaque;
  491 + void *mipid = mipid_init();
  492 +
  493 + omap_mcspi_attach(s->cpu->mcspi[0], tsc210x_txrx, tsc2301, 0);
  494 + omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, mipid, 1);
  495 +}
  496 +
  497 +/* This task is normally performed by the bootloader. If we're loading
  498 + * a kernel directly, we need to enable the Blizzard ourselves. */
  499 +static void n800_dss_init(struct rfbi_chip_s *chip)
  500 +{
  501 + uint8_t *fb_blank;
  502 +
  503 + chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */
  504 + chip->write(chip->opaque, 1, 0x64);
  505 + chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */
  506 + chip->write(chip->opaque, 1, 0x1e);
  507 + chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */
  508 + chip->write(chip->opaque, 1, 0xe0);
  509 + chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */
  510 + chip->write(chip->opaque, 1, 0x01);
  511 + chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */
  512 + chip->write(chip->opaque, 1, 0x06);
  513 + chip->write(chip->opaque, 0, 0x68); /* Display Mode register */
  514 + chip->write(chip->opaque, 1, 1); /* Enable bit */
  515 +
  516 + chip->write(chip->opaque, 0, 0x6c);
  517 + chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */
  518 + chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */
  519 + chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */
  520 + chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */
  521 + chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */
  522 + chip->write(chip->opaque, 1, 0x03); /* Input X End Position */
  523 + chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */
  524 + chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */
  525 + chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */
  526 + chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */
  527 + chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */
  528 + chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */
  529 + chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */
  530 + chip->write(chip->opaque, 1, 0x03); /* Output X End Position */
  531 + chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */
  532 + chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */
  533 + chip->write(chip->opaque, 1, 0x01); /* Input Data Format */
  534 + chip->write(chip->opaque, 1, 0x01); /* Data Source Select */
  535 +
  536 + fb_blank = memset(qemu_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
  537 + /* Display Memory Data Port */
  538 + chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
  539 + free(fb_blank);
  540 +}
  541 +
  542 +static void n800_dss_setup(struct n800_s *s, DisplayState *ds)
  543 +{
  544 + s->blizzard.opaque = s1d13745_init(0, ds);
  545 + s->blizzard.block = s1d13745_write_block;
  546 + s->blizzard.write = s1d13745_write;
  547 + s->blizzard.read = s1d13745_read;
  548 +
  549 + omap_rfbi_attach(s->cpu->dss, 0, &s->blizzard);
  550 +}
  551 +
  552 +static void n800_cbus_setup(struct n800_s *s)
  553 +{
  554 + qemu_irq dat_out = omap2_gpio_in_get(s->cpu->gpif, N8X0_CBUS_DAT_GPIO)[0];
  555 + qemu_irq retu_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_RETU_GPIO)[0];
  556 + qemu_irq tahvo_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TAHVO_GPIO)[0];
  557 +
  558 + struct cbus_s *cbus = cbus_init(dat_out);
  559 +
  560 + omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_CLK_GPIO, cbus->clk);
  561 + omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_DAT_GPIO, cbus->dat);
  562 + omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_SEL_GPIO, cbus->sel);
  563 +
  564 + cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
  565 + cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
  566 +}
  567 +
  568 +/* This task is normally performed by the bootloader. If we're loading
  569 + * a kernel directly, we need to set up GPMC mappings ourselves. */
  570 +static void n800_gpmc_init(struct n800_s *s)
  571 +{
  572 + uint32_t config7 =
  573 + (0xf << 8) | /* MASKADDRESS */
  574 + (1 << 6) | /* CSVALID */
  575 + (4 << 0); /* BASEADDRESS */
  576 +
  577 + cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */
  578 + (void *) &config7, sizeof(config7));
  579 +}
  580 +
  581 +/* Setup sequence done by the bootloader */
  582 +static void n800_boot_init(void *opaque)
  583 +{
  584 + struct n800_s *s = (struct n800_s *) opaque;
  585 + uint32_t buf;
  586 +
  587 + /* PRCM setup */
  588 +#define omap_writel(addr, val) \
  589 + buf = (val); \
  590 + cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf))
  591 +
  592 + omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */
  593 + omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */
  594 + omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */
  595 + omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */
  596 + omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */
  597 + omap_writel(0x48008098, 0); /* PRCM_POLCTRL */
  598 + omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */
  599 + omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */
  600 + omap_writel(0x48008158, 1); /* RM_RSTST_MPU */
  601 + omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */
  602 + omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */
  603 + omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */
  604 + omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */
  605 + omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */
  606 + omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */
  607 + omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */
  608 + omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */
  609 + omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */
  610 + omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */
  611 + omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */
  612 + omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */
  613 + omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */
  614 + omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */
  615 + omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */
  616 + omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */
  617 + omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */
  618 + omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */
  619 + omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */
  620 + omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */
  621 + omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */
  622 + omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */
  623 + omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */
  624 + omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */
  625 + omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */
  626 + omap_writel(0x48008540, /* CM_CLKSEL1_PLL */
  627 + (0x78 << 12) | (6 << 8));
  628 + omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */
  629 +
  630 + /* GPMC setup */
  631 + n800_gpmc_init(s);
  632 +
  633 + /* Video setup */
  634 + n800_dss_init(&s->blizzard);
  635 +
  636 + /* CPU setup */
  637 + s->cpu->env->regs[15] = s->cpu->env->boot_info->loader_start;
  638 + s->cpu->env->GE = 0x5;
  639 +}
  640 +
  641 +#define OMAP_TAG_NOKIA_BT 0x4e01
  642 +#define OMAP_TAG_WLAN_CX3110X 0x4e02
  643 +#define OMAP_TAG_CBUS 0x4e03
  644 +#define OMAP_TAG_EM_ASIC_BB5 0x4e04
  645 +
  646 +static int n800_atag_setup(struct arm_boot_info *info, void *p)
  647 +{
  648 + uint8_t *b;
  649 + uint16_t *w;
  650 + uint32_t *l;
  651 +
  652 + w = p;
  653 +
  654 + stw_raw(w ++, OMAP_TAG_UART); /* u16 tag */
  655 + stw_raw(w ++, 4); /* u16 len */
  656 + stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */
  657 + w ++;
  658 +
  659 + stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */
  660 + stw_raw(w ++, 4); /* u16 len */
  661 + stw_raw(w ++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */
  662 + stw_raw(w ++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */
  663 +
  664 + stw_raw(w ++, OMAP_TAG_CBUS); /* u16 tag */
  665 + stw_raw(w ++, 8); /* u16 len */
  666 + stw_raw(w ++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */
  667 + stw_raw(w ++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */
  668 + stw_raw(w ++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */
  669 + w ++;
  670 +
  671 + stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */
  672 + stw_raw(w ++, 20); /* u16 len */
  673 + strcpy((void *) w, "bat_cover"); /* char name[12] */
  674 + w += 6;
  675 + stw_raw(w ++, N800_BAT_COVER_GPIO); /* u16 gpio */
  676 + stw_raw(w ++, 0x01);
  677 + stw_raw(w ++, 0);
  678 + stw_raw(w ++, 0);
  679 +
  680 + stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */
  681 + stw_raw(w ++, 20); /* u16 len */
  682 + strcpy((void *) w, "cam_act"); /* char name[12] */
  683 + w += 6;
  684 + stw_raw(w ++, N800_CAM_ACT_GPIO); /* u16 gpio */
  685 + stw_raw(w ++, 0x20);
  686 + stw_raw(w ++, 0);
  687 + stw_raw(w ++, 0);
  688 +
  689 + stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */
  690 + stw_raw(w ++, 20); /* u16 len */
  691 + strcpy((void *) w, "cam_turn"); /* char name[12] */
  692 + w += 6;
  693 + stw_raw(w ++, N800_CAM_TURN_GPIO); /* u16 gpio */
  694 + stw_raw(w ++, 0x21);
  695 + stw_raw(w ++, 0);
  696 + stw_raw(w ++, 0);
  697 +
  698 + stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */
  699 + stw_raw(w ++, 20); /* u16 len */
  700 + strcpy((void *) w, "headphone"); /* char name[12] */
  701 + w += 6;
  702 + stw_raw(w ++, N800_HEADPHONE_GPIO); /* u16 gpio */
  703 + stw_raw(w ++, 0x11);
  704 + stw_raw(w ++, 0);
  705 + stw_raw(w ++, 0);
  706 +
  707 + stw_raw(w ++, OMAP_TAG_NOKIA_BT); /* u16 tag */
  708 + stw_raw(w ++, 12); /* u16 len */
  709 + b = (void *) w;
  710 + stb_raw(b ++, 0x01); /* u8 chip_type (CSR) */
  711 + stb_raw(b ++, N800_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */
  712 + stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */
  713 + stb_raw(b ++, N800_BT_RESET_GPIO); /* u8 reset_gpio */
  714 + stb_raw(b ++, 1); /* u8 bt_uart */
  715 + memset(b, 0, 6); /* u8 bd_addr[6] */
  716 + b += 6;
  717 + stb_raw(b ++, 0x02); /* u8 bt_sysclk (38.4) */
  718 + w = (void *) b;
  719 +
  720 + stw_raw(w ++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */
  721 + stw_raw(w ++, 8); /* u16 len */
  722 + stw_raw(w ++, 0x25); /* u8 chip_type */
  723 + stw_raw(w ++, N800_WLAN_PWR_GPIO); /* s16 power_gpio */
  724 + stw_raw(w ++, N800_WLAN_IRQ_GPIO); /* s16 irq_gpio */
  725 + stw_raw(w ++, -1); /* s16 spi_cs_gpio */
  726 +
  727 + stw_raw(w ++, OMAP_TAG_MMC); /* u16 tag */
  728 + stw_raw(w ++, 16); /* u16 len */
  729 + stw_raw(w ++, 0xf); /* unsigned flags */
  730 + stw_raw(w ++, -1); /* s16 power_pin */
  731 + stw_raw(w ++, -1); /* s16 switch_pin */
  732 + stw_raw(w ++, -1); /* s16 wp_pin */
  733 + stw_raw(w ++, 0); /* unsigned flags */
  734 + stw_raw(w ++, 0); /* s16 power_pin */
  735 + stw_raw(w ++, 0); /* s16 switch_pin */
  736 + stw_raw(w ++, 0); /* s16 wp_pin */
  737 +
  738 + stw_raw(w ++, OMAP_TAG_TEA5761); /* u16 tag */
  739 + stw_raw(w ++, 4); /* u16 len */
  740 + stw_raw(w ++, N800_TEA5761_CS_GPIO); /* u16 enable_gpio */
  741 + w ++;
  742 +
  743 + stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */
  744 + stw_raw(w ++, 28); /* u16 len */
  745 + strcpy((void *) w, "bootloader"); /* char name[16] */
  746 + l = (void *) (w + 8);
  747 + stl_raw(l ++, 0x00020000); /* unsigned int size */
  748 + stl_raw(l ++, 0x00000000); /* unsigned int offset */
  749 + stl_raw(l ++, 0x3); /* unsigned int mask_flags */
  750 + w = (void *) l;
  751 +
  752 + stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */
  753 + stw_raw(w ++, 28); /* u16 len */
  754 + strcpy((void *) w, "config"); /* char name[16] */
  755 + l = (void *) (w + 8);
  756 + stl_raw(l ++, 0x00060000); /* unsigned int size */
  757 + stl_raw(l ++, 0x00020000); /* unsigned int offset */
  758 + stl_raw(l ++, 0x0); /* unsigned int mask_flags */
  759 + w = (void *) l;
  760 +
  761 + stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */
  762 + stw_raw(w ++, 28); /* u16 len */
  763 + strcpy((void *) w, "kernel"); /* char name[16] */
  764 + l = (void *) (w + 8);
  765 + stl_raw(l ++, 0x00200000); /* unsigned int size */
  766 + stl_raw(l ++, 0x00080000); /* unsigned int offset */
  767 + stl_raw(l ++, 0x0); /* unsigned int mask_flags */
  768 + w = (void *) l;
  769 +
  770 + stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */
  771 + stw_raw(w ++, 28); /* u16 len */
  772 + strcpy((void *) w, "initfs"); /* char name[16] */
  773 + l = (void *) (w + 8);
  774 + stl_raw(l ++, 0x00200000); /* unsigned int size */
  775 + stl_raw(l ++, 0x00280000); /* unsigned int offset */
  776 + stl_raw(l ++, 0x3); /* unsigned int mask_flags */
  777 + w = (void *) l;
  778 +
  779 + stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */
  780 + stw_raw(w ++, 28); /* u16 len */
  781 + strcpy((void *) w, "rootfs"); /* char name[16] */
  782 + l = (void *) (w + 8);
  783 + stl_raw(l ++, 0x0fb80000); /* unsigned int size */
  784 + stl_raw(l ++, 0x00480000); /* unsigned int offset */
  785 + stl_raw(l ++, 0x3); /* unsigned int mask_flags */
  786 + w = (void *) l;
  787 +
  788 + stw_raw(w ++, OMAP_TAG_BOOT_REASON); /* u16 tag */
  789 + stw_raw(w ++, 12); /* u16 len */
  790 +#if 0
  791 + strcpy((void *) w, "por"); /* char reason_str[12] */
  792 + strcpy((void *) w, "charger"); /* char reason_str[12] */
  793 + strcpy((void *) w, "32wd_to"); /* char reason_str[12] */
  794 + strcpy((void *) w, "sw_rst"); /* char reason_str[12] */
  795 + strcpy((void *) w, "mbus"); /* char reason_str[12] */
  796 + strcpy((void *) w, "unknown"); /* char reason_str[12] */
  797 + strcpy((void *) w, "swdg_to"); /* char reason_str[12] */
  798 + strcpy((void *) w, "sec_vio"); /* char reason_str[12] */
  799 + strcpy((void *) w, "pwr_key"); /* char reason_str[12] */
  800 + strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */
  801 +#else
  802 + strcpy((void *) w, "pwr_key"); /* char reason_str[12] */
  803 +#endif
  804 + w += 6;
  805 +
  806 +#if 0 /* N810 */
  807 + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */
  808 + stw_raw(w ++, 24); /* u16 len */
  809 + strcpy((void *) w, "product"); /* char component[12] */
  810 + w += 6;
  811 + strcpy((void *) w, "RX-44"); /* char version[12] */
  812 + w += 6;
  813 +
  814 + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */
  815 + stw_raw(w ++, 24); /* u16 len */
  816 + strcpy((void *) w, "hw-build"); /* char component[12] */
  817 + w += 6;
  818 + strcpy((void *) w, "QEMU"); /* char version[12] */
  819 + w += 6;
  820 +
  821 + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */
  822 + stw_raw(w ++, 24); /* u16 len */
  823 + strcpy((void *) w, "nolo"); /* char component[12] */
  824 + w += 6;
  825 + strcpy((void *) w, "1.1.10-qemu"); /* char version[12] */
  826 + w += 6;
  827 +#else
  828 + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */
  829 + stw_raw(w ++, 24); /* u16 len */
  830 + strcpy((void *) w, "product"); /* char component[12] */
  831 + w += 6;
  832 + strcpy((void *) w, "RX-34"); /* char version[12] */
  833 + w += 6;
  834 +
  835 + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */
  836 + stw_raw(w ++, 24); /* u16 len */
  837 + strcpy((void *) w, "hw-build"); /* char component[12] */
  838 + w += 6;
  839 + strcpy((void *) w, "QEMU"); /* char version[12] */
  840 + w += 6;
  841 +
  842 + stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */
  843 + stw_raw(w ++, 24); /* u16 len */
  844 + strcpy((void *) w, "nolo"); /* char component[12] */
  845 + w += 6;
  846 + strcpy((void *) w, "1.1.6-qemu"); /* char version[12] */
  847 + w += 6;
  848 +#endif
  849 +
  850 + stw_raw(w ++, OMAP_TAG_LCD); /* u16 tag */
  851 + stw_raw(w ++, 36); /* u16 len */
  852 + strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */
  853 + w += 8;
  854 + strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */
  855 + w += 8;
  856 + stw_raw(w ++, 5); /* TODO s16 nreset_gpio */
  857 + stw_raw(w ++, 16); /* u8 data_lines */
  858 +
  859 + return (void *) w - p;
  860 +}
  861 +
  862 +static struct arm_boot_info n800_binfo = {
  863 + .loader_start = OMAP2_Q2_BASE,
  864 + /* Actually two chips of 0x4000000 bytes each */
  865 + .ram_size = 0x08000000,
  866 + .board_id = 0x4f7,
  867 + .atag_board = n800_atag_setup,
  868 +};
  869 +
  870 +static void n800_init(int ram_size, int vga_ram_size,
  871 + const char *boot_device, DisplayState *ds,
  872 + const char *kernel_filename, const char *kernel_cmdline,
  873 + const char *initrd_filename, const char *cpu_model)
  874 +{
  875 + struct n800_s *s = (struct n800_s *) qemu_mallocz(sizeof(*s));
  876 + int sdram_size = n800_binfo.ram_size;
  877 + int onenandram_size = 0x00010000;
  878 +
  879 + if (ram_size < sdram_size + onenandram_size + OMAP242X_SRAM_SIZE) {
  880 + fprintf(stderr, "This architecture uses %i bytes of memory\n",
  881 + sdram_size + onenandram_size + OMAP242X_SRAM_SIZE);
  882 + exit(1);
  883 + }
  884 +
  885 + s->cpu = omap2420_mpu_init(sdram_size, NULL, cpu_model);
  886 +
  887 + n800_gpio_setup(s);
  888 + n8x0_nand_setup(s);
  889 + n800_i2c_setup(s);
  890 + n800_tsc_setup(s);
  891 + n800_spi_setup(s);
  892 + n800_dss_setup(s, ds);
  893 + n800_cbus_setup(s);
  894 +
  895 + /* Setup initial (reset) machine state */
  896 +
  897 + /* Start at the OneNAND bootloader. */
  898 + s->cpu->env->regs[15] = 0;
  899 +
  900 + if (kernel_filename) {
  901 + /* Or at the linux loader. */
  902 + n800_binfo.kernel_filename = kernel_filename;
  903 + n800_binfo.kernel_cmdline = kernel_cmdline;
  904 + n800_binfo.initrd_filename = initrd_filename;
  905 + arm_load_kernel(s->cpu->env, &n800_binfo);
  906 +
  907 + qemu_register_reset(n800_boot_init, s);
  908 + n800_boot_init(s);
  909 + }
  910 +
  911 + dpy_resize(ds, 800, 480);
  912 +}
  913 +
  914 +QEMUMachine n800_machine = {
  915 + "n800",
  916 + "Nokia N800 aka. RX-34 tablet (OMAP2420)",
  917 + n800_init,
  918 +};
... ...
hw/omap2.c
... ... @@ -3496,7 +3496,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
3496 3496 {
3497 3497 struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
3498 3498 qemu_mallocz(sizeof(struct omap_mpu_state_s));
3499   - ram_addr_t sram_base, q3_base;
  3499 + ram_addr_t sram_base, q2_base;
3500 3500 qemu_irq *cpu_irq;
3501 3501 qemu_irq dma_irqs[4];
3502 3502 omap_clk gpio_clks[4];
... ... @@ -3520,7 +3520,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
3520 3520  
3521 3521 /* Memory-mapped stuff */
3522 3522 cpu_register_physical_memory(OMAP2_Q2_BASE, s->sdram_size,
3523   - (q3_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM);
  3523 + (q2_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM);
3524 3524 cpu_register_physical_memory(OMAP2_SRAM_BASE, s->sram_size,
3525 3525 (sram_base = qemu_ram_alloc(s->sram_size)) | IO_MEM_RAM);
3526 3526  
... ...
hw/onenand.c 0 → 100644
  1 +/*
  2 + * OneNAND flash memories emulation.
  3 + *
  4 + * Copyright (C) 2008 Nokia Corporation
  5 + * Written by Andrzej Zaborowski <andrew@openedhand.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 or
  10 + * (at your option) version 3 of the License.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#include "qemu-common.h"
  24 +#include "flash.h"
  25 +#include "irq.h"
  26 +#include "sysemu.h"
  27 +#include "block.h"
  28 +
  29 +/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
  30 +#define PAGE_SHIFT 11
  31 +
  32 +/* Fixed */
  33 +#define BLOCK_SHIFT (PAGE_SHIFT + 6)
  34 +
  35 +struct onenand_s {
  36 + uint32_t id;
  37 + int shift;
  38 + target_phys_addr_t base;
  39 + qemu_irq intr;
  40 + qemu_irq rdy;
  41 + BlockDriverState *bdrv;
  42 + BlockDriverState *bdrv_cur;
  43 + uint8_t *image;
  44 + uint8_t *otp;
  45 + uint8_t *current;
  46 + ram_addr_t ram;
  47 + uint8_t *boot[2];
  48 + uint8_t *data[2][2];
  49 + int iomemtype;
  50 + int cycle;
  51 + int otpmode;
  52 +
  53 + uint16_t addr[8];
  54 + uint16_t unladdr[8];
  55 + int bufaddr;
  56 + int count;
  57 + uint16_t command;
  58 + uint16_t config[2];
  59 + uint16_t status;
  60 + uint16_t intstatus;
  61 + uint16_t wpstatus;
  62 +
  63 + struct ecc_state_s ecc;
  64 +
  65 + int density_mask;
  66 + int secs;
  67 + int secs_cur;
  68 + int blocks;
  69 + uint8_t *blockwp;
  70 +};
  71 +
  72 +enum {
  73 + ONEN_BUF_BLOCK = 0,
  74 + ONEN_BUF_BLOCK2 = 1,
  75 + ONEN_BUF_DEST_BLOCK = 2,
  76 + ONEN_BUF_DEST_PAGE = 3,
  77 + ONEN_BUF_PAGE = 7,
  78 +};
  79 +
  80 +enum {
  81 + ONEN_ERR_CMD = 1 << 10,
  82 + ONEN_ERR_ERASE = 1 << 11,
  83 + ONEN_ERR_PROG = 1 << 12,
  84 + ONEN_ERR_LOAD = 1 << 13,
  85 +};
  86 +
  87 +enum {
  88 + ONEN_INT_RESET = 1 << 4,
  89 + ONEN_INT_ERASE = 1 << 5,
  90 + ONEN_INT_PROG = 1 << 6,
  91 + ONEN_INT_LOAD = 1 << 7,
  92 + ONEN_INT = 1 << 15,
  93 +};
  94 +
  95 +enum {
  96 + ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
  97 + ONEN_LOCK_LOCKED = 1 << 1,
  98 + ONEN_LOCK_UNLOCKED = 1 << 2,
  99 +};
  100 +
  101 +void onenand_base_update(void *opaque, target_phys_addr_t new)
  102 +{
  103 + struct onenand_s *s = (struct onenand_s *) opaque;
  104 +
  105 + s->base = new;
  106 +
  107 + /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
  108 + * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
  109 + * write boot commands. Also take note of the BWPS bit. */
  110 + cpu_register_physical_memory(s->base + (0x0000 << s->shift),
  111 + 0x0200 << s->shift, s->iomemtype);
  112 + cpu_register_physical_memory(s->base + (0x0200 << s->shift),
  113 + 0xbe00 << s->shift,
  114 + (s->ram +(0x0200 << s->shift)) | IO_MEM_RAM);
  115 + if (s->iomemtype)
  116 + cpu_register_physical_memory(s->base + (0xc000 << s->shift),
  117 + 0x4000 << s->shift, s->iomemtype);
  118 +}
  119 +
  120 +void onenand_base_unmap(void *opaque)
  121 +{
  122 + struct onenand_s *s = (struct onenand_s *) opaque;
  123 +
  124 + cpu_register_physical_memory(s->base,
  125 + 0x10000 << s->shift, IO_MEM_UNASSIGNED);
  126 +}
  127 +
  128 +static void onenand_intr_update(struct onenand_s *s)
  129 +{
  130 + qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
  131 +}
  132 +
  133 +/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
  134 +static void onenand_reset(struct onenand_s *s, int cold)
  135 +{
  136 + memset(&s->addr, 0, sizeof(s->addr));
  137 + s->command = 0;
  138 + s->count = 1;
  139 + s->bufaddr = 0;
  140 + s->config[0] = 0x40c0;
  141 + s->config[1] = 0x0000;
  142 + onenand_intr_update(s);
  143 + qemu_irq_raise(s->rdy);
  144 + s->status = 0x0000;
  145 + s->intstatus = cold ? 0x8080 : 0x8010;
  146 + s->unladdr[0] = 0;
  147 + s->unladdr[1] = 0;
  148 + s->wpstatus = 0x0002;
  149 + s->cycle = 0;
  150 + s->otpmode = 0;
  151 + s->bdrv_cur = s->bdrv;
  152 + s->current = s->image;
  153 + s->secs_cur = s->secs;
  154 +
  155 + if (cold) {
  156 + /* Lock the whole flash */
  157 + memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
  158 +
  159 + if (s->bdrv && bdrv_read(s->bdrv, 0, s->boot[0], 8) < 0)
  160 + cpu_abort(cpu_single_env, "%s: Loading the BootRAM failed.\n",
  161 + __FUNCTION__);
  162 + }
  163 +}
  164 +
  165 +static inline int onenand_load_main(struct onenand_s *s, int sec, int secn,
  166 + void *dest)
  167 +{
  168 + if (s->bdrv_cur)
  169 + return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0;
  170 + else if (sec + secn > s->secs_cur)
  171 + return 1;
  172 +
  173 + memcpy(dest, s->current + (sec << 9), secn << 9);
  174 +
  175 + return 0;
  176 +}
  177 +
  178 +static inline int onenand_prog_main(struct onenand_s *s, int sec, int secn,
  179 + void *src)
  180 +{
  181 + if (s->bdrv_cur)
  182 + return bdrv_write(s->bdrv_cur, sec, src, secn) < 0;
  183 + else if (sec + secn > s->secs_cur)
  184 + return 1;
  185 +
  186 + memcpy(s->current + (sec << 9), src, secn << 9);
  187 +
  188 + return 0;
  189 +}
  190 +
  191 +static inline int onenand_load_spare(struct onenand_s *s, int sec, int secn,
  192 + void *dest)
  193 +{
  194 + uint8_t buf[512];
  195 +
  196 + if (s->bdrv_cur) {
  197 + if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
  198 + return 1;
  199 + memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
  200 + } else if (sec + secn > s->secs_cur)
  201 + return 1;
  202 + else
  203 + memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
  204 +
  205 + return 0;
  206 +}
  207 +
  208 +static inline int onenand_prog_spare(struct onenand_s *s, int sec, int secn,
  209 + void *src)
  210 +{
  211 + uint8_t buf[512];
  212 +
  213 + if (s->bdrv_cur) {
  214 + if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
  215 + return 1;
  216 + memcpy(buf + ((sec & 31) << 4), src, secn << 4);
  217 + return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0;
  218 + } else if (sec + secn > s->secs_cur)
  219 + return 1;
  220 +
  221 + memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4);
  222 +
  223 + return 0;
  224 +}
  225 +
  226 +static inline int onenand_erase(struct onenand_s *s, int sec, int num)
  227 +{
  228 + /* TODO: optimise */
  229 + uint8_t buf[512];
  230 +
  231 + memset(buf, 0xff, sizeof(buf));
  232 + for (; num > 0; num --, sec ++) {
  233 + if (onenand_prog_main(s, sec, 1, buf))
  234 + return 1;
  235 + if (onenand_prog_spare(s, sec, 1, buf))
  236 + return 1;
  237 + }
  238 +
  239 + return 0;
  240 +}
  241 +
  242 +static void onenand_command(struct onenand_s *s, int cmd)
  243 +{
  244 + int b;
  245 + int sec;
  246 + void *buf;
  247 +#define SETADDR(block, page) \
  248 + sec = (s->addr[page] & 3) + \
  249 + ((((s->addr[page] >> 2) & 0x3f) + \
  250 + (((s->addr[block] & 0xfff) | \
  251 + (s->addr[block] >> 15 ? \
  252 + s->density_mask : 0)) << 6)) << (PAGE_SHIFT - 9));
  253 +#define SETBUF_M() \
  254 + buf = (s->bufaddr & 8) ? \
  255 + s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0]; \
  256 + buf += (s->bufaddr & 3) << 9;
  257 +#define SETBUF_S() \
  258 + buf = (s->bufaddr & 8) ? \
  259 + s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1]; \
  260 + buf += (s->bufaddr & 3) << 4;
  261 +
  262 + switch (cmd) {
  263 + case 0x00: /* Load single/multiple sector data unit into buffer */
  264 + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
  265 +
  266 + SETBUF_M()
  267 + if (onenand_load_main(s, sec, s->count, buf))
  268 + s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
  269 +
  270 +#if 0
  271 + SETBUF_S()
  272 + if (onenand_load_spare(s, sec, s->count, buf))
  273 + s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
  274 +#endif
  275 +
  276 + /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
  277 + * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
  278 + * then we need two split the read/write into two chunks.
  279 + */
  280 + s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
  281 + break;
  282 + case 0x13: /* Load single/multiple spare sector into buffer */
  283 + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
  284 +
  285 + SETBUF_S()
  286 + if (onenand_load_spare(s, sec, s->count, buf))
  287 + s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
  288 +
  289 + /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
  290 + * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
  291 + * then we need two split the read/write into two chunks.
  292 + */
  293 + s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
  294 + break;
  295 + case 0x80: /* Program single/multiple sector data unit from buffer */
  296 + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
  297 +
  298 + SETBUF_M()
  299 + if (onenand_prog_main(s, sec, s->count, buf))
  300 + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
  301 +
  302 +#if 0
  303 + SETBUF_S()
  304 + if (onenand_prog_spare(s, sec, s->count, buf))
  305 + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
  306 +#endif
  307 +
  308 + /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
  309 + * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
  310 + * then we need two split the read/write into two chunks.
  311 + */
  312 + s->intstatus |= ONEN_INT | ONEN_INT_PROG;
  313 + break;
  314 + case 0x1a: /* Program single/multiple spare area sector from buffer */
  315 + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
  316 +
  317 + SETBUF_S()
  318 + if (onenand_prog_spare(s, sec, s->count, buf))
  319 + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
  320 +
  321 + /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
  322 + * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
  323 + * then we need two split the read/write into two chunks.
  324 + */
  325 + s->intstatus |= ONEN_INT | ONEN_INT_PROG;
  326 + break;
  327 + case 0x1b: /* Copy-back program */
  328 + SETBUF_S()
  329 +
  330 + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
  331 + if (onenand_load_main(s, sec, s->count, buf))
  332 + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
  333 +
  334 + SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
  335 + if (onenand_prog_main(s, sec, s->count, buf))
  336 + s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
  337 +
  338 + /* TODO: spare areas */
  339 +
  340 + s->intstatus |= ONEN_INT | ONEN_INT_PROG;
  341 + break;
  342 +
  343 + case 0x23: /* Unlock NAND array block(s) */
  344 + s->intstatus |= ONEN_INT;
  345 +
  346 + /* XXX the previous (?) area should be locked automatically */
  347 + for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
  348 + if (b >= s->blocks) {
  349 + s->status |= ONEN_ERR_CMD;
  350 + break;
  351 + }
  352 + if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
  353 + break;
  354 +
  355 + s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
  356 + }
  357 + break;
  358 + case 0x2a: /* Lock NAND array block(s) */
  359 + s->intstatus |= ONEN_INT;
  360 +
  361 + for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
  362 + if (b >= s->blocks) {
  363 + s->status |= ONEN_ERR_CMD;
  364 + break;
  365 + }
  366 + if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
  367 + break;
  368 +
  369 + s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
  370 + }
  371 + break;
  372 + case 0x2c: /* Lock-tight NAND array block(s) */
  373 + s->intstatus |= ONEN_INT;
  374 +
  375 + for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
  376 + if (b >= s->blocks) {
  377 + s->status |= ONEN_ERR_CMD;
  378 + break;
  379 + }
  380 + if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
  381 + continue;
  382 +
  383 + s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
  384 + }
  385 + break;
  386 +
  387 + case 0x71: /* Erase-Verify-Read */
  388 + s->intstatus |= ONEN_INT;
  389 + break;
  390 + case 0x95: /* Multi-block erase */
  391 + qemu_irq_pulse(s->intr);
  392 + /* Fall through. */
  393 + case 0x94: /* Block erase */
  394 + sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
  395 + (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
  396 + << (BLOCK_SHIFT - 9);
  397 + if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
  398 + s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
  399 +
  400 + s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
  401 + break;
  402 + case 0xb0: /* Erase suspend */
  403 + break;
  404 + case 0x30: /* Erase resume */
  405 + s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
  406 + break;
  407 +
  408 + case 0xf0: /* Reset NAND Flash core */
  409 + onenand_reset(s, 0);
  410 + break;
  411 + case 0xf3: /* Reset OneNAND */
  412 + onenand_reset(s, 0);
  413 + break;
  414 +
  415 + case 0x65: /* OTP Access */
  416 + s->intstatus |= ONEN_INT;
  417 + s->bdrv_cur = 0;
  418 + s->current = s->otp;
  419 + s->secs_cur = 1 << (BLOCK_SHIFT - 9);
  420 + s->addr[ONEN_BUF_BLOCK] = 0;
  421 + s->otpmode = 1;
  422 + break;
  423 +
  424 + default:
  425 + s->status |= ONEN_ERR_CMD;
  426 + s->intstatus |= ONEN_INT;
  427 + fprintf(stderr, "%s: unknown OneNAND command %x\n",
  428 + __FUNCTION__, cmd);
  429 + }
  430 +
  431 + onenand_intr_update(s);
  432 +}
  433 +
  434 +static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
  435 +{
  436 + struct onenand_s *s = (struct onenand_s *) opaque;
  437 + int offset = (addr - s->base) >> s->shift;
  438 +
  439 + switch (offset) {
  440 + case 0x0000 ... 0xc000:
  441 + return lduw_le_p(s->boot[0] + (addr - s->base));
  442 +
  443 + case 0xf000: /* Manufacturer ID */
  444 + return (s->id >> 16) & 0xff;
  445 + case 0xf001: /* Device ID */
  446 + return (s->id >> 8) & 0xff;
  447 + /* TODO: get the following values from a real chip! */
  448 + case 0xf002: /* Version ID */
  449 + return (s->id >> 0) & 0xff;
  450 + case 0xf003: /* Data Buffer size */
  451 + return 1 << PAGE_SHIFT;
  452 + case 0xf004: /* Boot Buffer size */
  453 + return 0x200;
  454 + case 0xf005: /* Amount of buffers */
  455 + return 1 | (2 << 8);
  456 + case 0xf006: /* Technology */
  457 + return 0;
  458 +
  459 + case 0xf100 ... 0xf107: /* Start addresses */
  460 + return s->addr[offset - 0xf100];
  461 +
  462 + case 0xf200: /* Start buffer */
  463 + return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
  464 +
  465 + case 0xf220: /* Command */
  466 + return s->command;
  467 + case 0xf221: /* System Configuration 1 */
  468 + return s->config[0] & 0xffe0;
  469 + case 0xf222: /* System Configuration 2 */
  470 + return s->config[1];
  471 +
  472 + case 0xf240: /* Controller Status */
  473 + return s->status;
  474 + case 0xf241: /* Interrupt */
  475 + return s->intstatus;
  476 + case 0xf24c: /* Unlock Start Block Address */
  477 + return s->unladdr[0];
  478 + case 0xf24d: /* Unlock End Block Address */
  479 + return s->unladdr[1];
  480 + case 0xf24e: /* Write Protection Status */
  481 + return s->wpstatus;
  482 +
  483 + case 0xff00: /* ECC Status */
  484 + return 0x00;
  485 + case 0xff01: /* ECC Result of main area data */
  486 + case 0xff02: /* ECC Result of spare area data */
  487 + case 0xff03: /* ECC Result of main area data */
  488 + case 0xff04: /* ECC Result of spare area data */
  489 + cpu_abort(cpu_single_env, "%s: imeplement ECC\n", __FUNCTION__);
  490 + return 0x0000;
  491 + }
  492 +
  493 + fprintf(stderr, "%s: unknown OneNAND register %x\n",
  494 + __FUNCTION__, offset);
  495 + return 0;
  496 +}
  497 +
  498 +static void onenand_write(void *opaque, target_phys_addr_t addr,
  499 + uint32_t value)
  500 +{
  501 + struct onenand_s *s = (struct onenand_s *) opaque;
  502 + int offset = (addr - s->base) >> s->shift;
  503 + int sec;
  504 +
  505 + switch (offset) {
  506 + case 0x0000 ... 0x01ff:
  507 + case 0x8000 ... 0x800f:
  508 + if (s->cycle) {
  509 + s->cycle = 0;
  510 +
  511 + if (value == 0x0000) {
  512 + SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
  513 + onenand_load_main(s, sec,
  514 + 1 << (PAGE_SHIFT - 9), s->data[0][0]);
  515 + s->addr[ONEN_BUF_PAGE] += 4;
  516 + s->addr[ONEN_BUF_PAGE] &= 0xff;
  517 + }
  518 + break;
  519 + }
  520 +
  521 + switch (value) {
  522 + case 0x00f0: /* Reset OneNAND */
  523 + onenand_reset(s, 0);
  524 + break;
  525 +
  526 + case 0x00e0: /* Load Data into Buffer */
  527 + s->cycle = 1;
  528 + break;
  529 +
  530 + case 0x0090: /* Read Identification Data */
  531 + memset(s->boot[0], 0, 3 << s->shift);
  532 + s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff;
  533 + s->boot[0][1 << s->shift] = (s->id >> 8) & 0xff;
  534 + s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
  535 + break;
  536 +
  537 + default:
  538 + fprintf(stderr, "%s: unknown OneNAND boot command %x\n",
  539 + __FUNCTION__, value);
  540 + }
  541 + break;
  542 +
  543 + case 0xf100 ... 0xf107: /* Start addresses */
  544 + s->addr[offset - 0xf100] = value;
  545 + break;
  546 +
  547 + case 0xf200: /* Start buffer */
  548 + s->bufaddr = (value >> 8) & 0xf;
  549 + if (PAGE_SHIFT == 11)
  550 + s->count = (value & 3) ?: 4;
  551 + else if (PAGE_SHIFT == 10)
  552 + s->count = (value & 1) ?: 2;
  553 + break;
  554 +
  555 + case 0xf220: /* Command */
  556 + if (s->intstatus & (1 << 15))
  557 + break;
  558 + s->command = value;
  559 + onenand_command(s, s->command);
  560 + break;
  561 + case 0xf221: /* System Configuration 1 */
  562 + s->config[0] = value;
  563 + onenand_intr_update(s);
  564 + qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
  565 + break;
  566 + case 0xf222: /* System Configuration 2 */
  567 + s->config[1] = value;
  568 + break;
  569 +
  570 + case 0xf241: /* Interrupt */
  571 + s->intstatus &= value;
  572 + if ((1 << 15) & ~s->intstatus)
  573 + s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
  574 + ONEN_ERR_PROG | ONEN_ERR_LOAD);
  575 + onenand_intr_update(s);
  576 + break;
  577 + case 0xf24c: /* Unlock Start Block Address */
  578 + s->unladdr[0] = value & (s->blocks - 1);
  579 + /* For some reason we have to set the end address to by default
  580 + * be same as start because the software forgets to write anything
  581 + * in there. */
  582 + s->unladdr[1] = value & (s->blocks - 1);
  583 + break;
  584 + case 0xf24d: /* Unlock End Block Address */
  585 + s->unladdr[1] = value & (s->blocks - 1);
  586 + break;
  587 +
  588 + default:
  589 + fprintf(stderr, "%s: unknown OneNAND register %x\n",
  590 + __FUNCTION__, offset);
  591 + }
  592 +}
  593 +
  594 +static CPUReadMemoryFunc *onenand_readfn[] = {
  595 + onenand_read, /* TODO */
  596 + onenand_read,
  597 + onenand_read,
  598 +};
  599 +
  600 +static CPUWriteMemoryFunc *onenand_writefn[] = {
  601 + onenand_write, /* TODO */
  602 + onenand_write,
  603 + onenand_write,
  604 +};
  605 +
  606 +void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
  607 +{
  608 + struct onenand_s *s = (struct onenand_s *) qemu_mallocz(sizeof(*s));
  609 + int bdrv_index = drive_get_index(IF_MTD, 0, 0);
  610 + uint32_t size = 1 << (24 + ((id >> 12) & 7));
  611 + void *ram;
  612 +
  613 + s->shift = regshift;
  614 + s->intr = irq;
  615 + s->rdy = 0;
  616 + s->id = id;
  617 + s->blocks = size >> BLOCK_SHIFT;
  618 + s->secs = size >> 9;
  619 + s->blockwp = qemu_malloc(s->blocks);
  620 + s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
  621 + s->iomemtype = cpu_register_io_memory(0, onenand_readfn,
  622 + onenand_writefn, s);
  623 + if (bdrv_index == -1)
  624 + s->image = memset(qemu_malloc(size + (size >> 5)),
  625 + 0xff, size + (size >> 5));
  626 + else
  627 + s->bdrv = drives_table[bdrv_index].bdrv;
  628 + s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
  629 + 0xff, (64 + 2) << PAGE_SHIFT);
  630 + s->ram = qemu_ram_alloc(0xc000 << s->shift);
  631 + ram = phys_ram_base + s->ram;
  632 + s->boot[0] = ram + (0x0000 << s->shift);
  633 + s->boot[1] = ram + (0x8000 << s->shift);
  634 + s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
  635 + s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
  636 + s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
  637 + s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
  638 +
  639 + onenand_reset(s, 1);
  640 +
  641 + return s;
  642 +}
... ...
hw/tmp105.c 0 → 100644
  1 +/*
  2 + * Texas Instruments TMP105 temperature sensor.
  3 + *
  4 + * Copyright (C) 2008 Nokia Corporation
  5 + * Written by Andrzej Zaborowski <andrew@openedhand.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 or
  10 + * (at your option) version 3 of the License.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#include "hw.h"
  24 +#include "i2c.h"
  25 +
  26 +struct tmp105_s {
  27 + i2c_slave i2c;
  28 + int len;
  29 + uint8_t buf[2];
  30 + qemu_irq pin;
  31 +
  32 + uint8_t pointer;
  33 + uint8_t config;
  34 + int16_t temperature;
  35 + int16_t limit[2];
  36 + int faults;
  37 + int alarm;
  38 +};
  39 +
  40 +static void tmp105_interrupt_update(struct tmp105_s *s)
  41 +{
  42 + qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */
  43 +}
  44 +
  45 +static void tmp105_alarm_update(struct tmp105_s *s)
  46 +{
  47 + if ((s->config >> 0) & 1) { /* SD */
  48 + if ((s->config >> 7) & 1) /* OS */
  49 + s->config &= ~(1 << 7); /* OS */
  50 + else
  51 + return;
  52 + }
  53 +
  54 + if ((s->config >> 1) & 1) { /* TM */
  55 + if (s->temperature >= s->limit[1])
  56 + s->alarm = 1;
  57 + else if (s->temperature < s->limit[0])
  58 + s->alarm = 1;
  59 + } else {
  60 + if (s->temperature >= s->limit[1])
  61 + s->alarm = 1;
  62 + else if (s->temperature < s->limit[0])
  63 + s->alarm = 0;
  64 + }
  65 +
  66 + tmp105_interrupt_update(s);
  67 +}
  68 +
  69 +/* Units are 0.001 centigrades relative to 0 C. */
  70 +void tmp105_set(i2c_slave *i2c, int temp)
  71 +{
  72 + struct tmp105_s *s = (struct tmp105_s *) i2c;
  73 +
  74 + if (temp >= 128000 || temp < -128000) {
  75 + fprintf(stderr, "%s: values is out of range (%i.%03i C)\n",
  76 + __FUNCTION__, temp / 1000, temp % 1000);
  77 + exit(-1);
  78 + }
  79 +
  80 + s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
  81 +
  82 + tmp105_alarm_update(s);
  83 +}
  84 +
  85 +static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
  86 +
  87 +static void tmp105_read(struct tmp105_s *s)
  88 +{
  89 + s->len = 0;
  90 +
  91 + if ((s->config >> 1) & 1) { /* TM */
  92 + s->alarm = 0;
  93 + tmp105_interrupt_update(s);
  94 + }
  95 +
  96 + switch (s->pointer & 3) {
  97 + case 0: /* Temperature */
  98 + s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
  99 + s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
  100 + (0xf0 << ((~s->config >> 5) & 3)); /* R */
  101 + break;
  102 +
  103 + case 1: /* Configuration */
  104 + s->buf[s->len ++] = s->config;
  105 + break;
  106 +
  107 + case 2: /* T_LOW */
  108 + s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
  109 + s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
  110 + break;
  111 +
  112 + case 3: /* T_HIGH */
  113 + s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
  114 + s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
  115 + break;
  116 + }
  117 +}
  118 +
  119 +static void tmp105_write(struct tmp105_s *s)
  120 +{
  121 + switch (s->pointer & 3) {
  122 + case 0: /* Temperature */
  123 + break;
  124 +
  125 + case 1: /* Configuration */
  126 + if (s->buf[0] & ~s->config & (1 << 0)) /* SD */
  127 + printf("%s: TMP105 shutdown\n", __FUNCTION__);
  128 + s->config = s->buf[0];
  129 + s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
  130 + tmp105_alarm_update(s);
  131 + break;
  132 +
  133 + case 2: /* T_LOW */
  134 + case 3: /* T_HIGH */
  135 + if (s->len >= 3)
  136 + s->limit[s->pointer & 1] = (int16_t)
  137 + ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
  138 + tmp105_alarm_update(s);
  139 + break;
  140 + }
  141 +}
  142 +
  143 +static int tmp105_rx(i2c_slave *i2c)
  144 +{
  145 + struct tmp105_s *s = (struct tmp105_s *) i2c;
  146 +
  147 + if (s->len < 2)
  148 + return s->buf[s->len ++];
  149 + else
  150 + return 0xff;
  151 +}
  152 +
  153 +static int tmp105_tx(i2c_slave *i2c, uint8_t data)
  154 +{
  155 + struct tmp105_s *s = (struct tmp105_s *) i2c;
  156 +
  157 + if (!s->len ++)
  158 + s->pointer = data;
  159 + else {
  160 + if (s->len <= 2)
  161 + s->buf[s->len - 1] = data;
  162 + tmp105_write(s);
  163 + }
  164 +
  165 + return 0;
  166 +}
  167 +
  168 +static void tmp105_event(i2c_slave *i2c, enum i2c_event event)
  169 +{
  170 + struct tmp105_s *s = (struct tmp105_s *) i2c;
  171 +
  172 + if (event == I2C_START_RECV)
  173 + tmp105_read(s);
  174 +
  175 + s->len = 0;
  176 +}
  177 +
  178 +static void tmp105_save(QEMUFile *f, void *opaque)
  179 +{
  180 + struct tmp105_s *s = (struct tmp105_s *) opaque;
  181 +
  182 + qemu_put_byte(f, s->len);
  183 + qemu_put_8s(f, &s->buf[0]);
  184 + qemu_put_8s(f, &s->buf[1]);
  185 +
  186 + qemu_put_8s(f, &s->pointer);
  187 + qemu_put_8s(f, &s->config);
  188 + qemu_put_be16s(f, &s->temperature);
  189 + qemu_put_be16s(f, &s->limit[0]);
  190 + qemu_put_be16s(f, &s->limit[1]);
  191 + qemu_put_byte(f, s->alarm);
  192 + s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
  193 +
  194 + i2c_slave_save(f, &s->i2c);
  195 +}
  196 +
  197 +static int tmp105_load(QEMUFile *f, void *opaque, int version_id)
  198 +{
  199 + struct tmp105_s *s = (struct tmp105_s *) opaque;
  200 +
  201 + s->len = qemu_get_byte(f);
  202 + qemu_get_8s(f, &s->buf[0]);
  203 + qemu_get_8s(f, &s->buf[1]);
  204 +
  205 + qemu_get_8s(f, &s->pointer);
  206 + qemu_get_8s(f, &s->config);
  207 + qemu_get_be16s(f, &s->temperature);
  208 + qemu_get_be16s(f, &s->limit[0]);
  209 + qemu_get_be16s(f, &s->limit[1]);
  210 + s->alarm = qemu_get_byte(f);
  211 +
  212 + tmp105_interrupt_update(s);
  213 +
  214 + i2c_slave_load(f, &s->i2c);
  215 + return 0;
  216 +}
  217 +
  218 +void tmp105_reset(i2c_slave *i2c)
  219 +{
  220 + struct tmp105_s *s = (struct tmp105_s *) i2c;
  221 +
  222 + s->temperature = 0;
  223 + s->pointer = 0;
  224 + s->config = 0;
  225 + s->faults = tmp105_faultq[(s->config >> 3) & 3];
  226 + s->alarm = 0;
  227 +
  228 + tmp105_interrupt_update(s);
  229 +}
  230 +
  231 +static int tmp105_iid = 0;
  232 +
  233 +struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm)
  234 +{
  235 + struct tmp105_s *s = (struct tmp105_s *)
  236 + i2c_slave_init(bus, 0, sizeof(struct tmp105_s));
  237 +
  238 + s->i2c.event = tmp105_event;
  239 + s->i2c.recv = tmp105_rx;
  240 + s->i2c.send = tmp105_tx;
  241 + s->pin = alarm;
  242 +
  243 + tmp105_reset(&s->i2c);
  244 +
  245 + register_savevm("TMP105", tmp105_iid ++, 0,
  246 + tmp105_save, tmp105_load, s);
  247 +
  248 + return &s->i2c;
  249 +}
... ...
hw/twl92230.c 0 → 100644
  1 +/*
  2 + * TI TWL92230C energy-management companion device for the OMAP24xx.
  3 + * Aka. Menelaus (N4200 MENELAUS1_V2.2)
  4 + *
  5 + * Copyright (C) 2008 Nokia Corporation
  6 + * Written by Andrzej Zaborowski <andrew@openedhand.com>
  7 + *
  8 + * This program is free software; you can redistribute it and/or
  9 + * modify it under the terms of the GNU General Public License as
  10 + * published by the Free Software Foundation; either version 2 or
  11 + * (at your option) version 3 of the License.
  12 + *
  13 + * This program is distributed in the hope that it will be useful,
  14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + * GNU General Public License for more details.
  17 + *
  18 + * You should have received a copy of the GNU General Public License
  19 + * along with this program; if not, write to the Free Software
  20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 + * MA 02111-1307 USA
  22 + */
  23 +
  24 +#include "hw.h"
  25 +#include "qemu-timer.h"
  26 +#include "i2c.h"
  27 +#include "sysemu.h"
  28 +#include "console.h"
  29 +
  30 +#define VERBOSE 1
  31 +
  32 +struct menelaus_s {
  33 + i2c_slave i2c;
  34 + qemu_irq irq;
  35 +
  36 + int firstbyte;
  37 + uint8_t reg;
  38 +
  39 + uint8_t vcore[5];
  40 + uint8_t dcdc[3];
  41 + uint8_t ldo[8];
  42 + uint8_t sleep[2];
  43 + uint8_t osc;
  44 + uint8_t detect;
  45 + uint16_t mask;
  46 + uint16_t status;
  47 + uint8_t dir;
  48 + uint8_t inputs;
  49 + uint8_t outputs;
  50 + uint8_t bbsms;
  51 + uint8_t pull[4];
  52 + uint8_t mmc_ctrl[3];
  53 + uint8_t mmc_debounce;
  54 + struct {
  55 + uint8_t ctrl;
  56 + uint16_t comp;
  57 + QEMUTimer *hz;
  58 + int64_t next;
  59 + struct tm tm;
  60 + struct tm new;
  61 + struct tm alm;
  62 + time_t sec;
  63 + time_t alm_sec;
  64 + time_t next_comp;
  65 + struct tm *(*gettime)(const time_t *timep, struct tm *result);
  66 + } rtc;
  67 + qemu_irq handler[3];
  68 + qemu_irq *in;
  69 + int pwrbtn_state;
  70 + qemu_irq pwrbtn;
  71 +};
  72 +
  73 +static inline void menelaus_update(struct menelaus_s *s)
  74 +{
  75 + qemu_set_irq(s->irq, s->status & ~s->mask);
  76 +}
  77 +
  78 +static inline void menelaus_rtc_start(struct menelaus_s *s)
  79 +{
  80 + s->rtc.next =+ qemu_get_clock(rt_clock);
  81 + qemu_mod_timer(s->rtc.hz, s->rtc.next);
  82 +}
  83 +
  84 +static inline void menelaus_rtc_stop(struct menelaus_s *s)
  85 +{
  86 + qemu_del_timer(s->rtc.hz);
  87 + s->rtc.next =- qemu_get_clock(rt_clock);
  88 + if (s->rtc.next < 1)
  89 + s->rtc.next = 1;
  90 +}
  91 +
  92 +static void menelaus_rtc_update(struct menelaus_s *s)
  93 +{
  94 + s->rtc.gettime(&s->rtc.sec, &s->rtc.tm);
  95 +}
  96 +
  97 +static void menelaus_alm_update(struct menelaus_s *s)
  98 +{
  99 + if ((s->rtc.ctrl & 3) == 3)
  100 + s->rtc.alm_sec = mktime(&s->rtc.alm);
  101 +}
  102 +
  103 +static void menelaus_rtc_hz(void *opaque)
  104 +{
  105 + struct menelaus_s *s = (struct menelaus_s *) opaque;
  106 +
  107 + s->rtc.sec ++;
  108 + s->rtc.next += 1000;
  109 + qemu_mod_timer(s->rtc.hz, s->rtc.next);
  110 + if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */
  111 + menelaus_rtc_update(s);
  112 + if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec)
  113 + s->status |= 1 << 8; /* RTCTMR */
  114 + else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min)
  115 + s->status |= 1 << 8; /* RTCTMR */
  116 + else if (!s->rtc.tm.tm_hour)
  117 + s->status |= 1 << 8; /* RTCTMR */
  118 + } else
  119 + s->status |= 1 << 8; /* RTCTMR */
  120 + if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */
  121 + if (s->rtc.sec == s->rtc.alm_sec)
  122 + s->status |= 1 << 9; /* RTCALM */
  123 + /* TODO: wake-up */
  124 + }
  125 + if (s->rtc.next_comp >= s->rtc.sec) {
  126 + s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000);
  127 + s->rtc.next_comp = s->rtc.sec + 3600;
  128 + }
  129 + menelaus_update(s);
  130 +}
  131 +
  132 +void menelaus_reset(i2c_slave *i2c)
  133 +{
  134 + struct menelaus_s *s = (struct menelaus_s *) i2c;
  135 + time_t ti;
  136 + s->reg = 0x00;
  137 +
  138 + s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */
  139 + s->vcore[1] = 0x05;
  140 + s->vcore[2] = 0x02;
  141 + s->vcore[3] = 0x0c;
  142 + s->vcore[4] = 0x03;
  143 + s->dcdc[0] = 0x33; /* Depends on wiring */
  144 + s->dcdc[1] = 0x03;
  145 + s->dcdc[2] = 0x00;
  146 + s->ldo[0] = 0x95;
  147 + s->ldo[1] = 0x7e;
  148 + s->ldo[2] = 0x00;
  149 + s->ldo[3] = 0x00; /* Depends on wiring */
  150 + s->ldo[4] = 0x03; /* Depends on wiring */
  151 + s->ldo[5] = 0x00;
  152 + s->ldo[6] = 0x00;
  153 + s->ldo[7] = 0x00;
  154 + s->sleep[0] = 0x00;
  155 + s->sleep[1] = 0x00;
  156 + s->osc = 0x01;
  157 + s->detect = 0x09;
  158 + s->mask = 0x0fff;
  159 + s->status = 0;
  160 + s->dir = 0x07;
  161 + s->outputs = 0x00;
  162 + s->bbsms = 0x00;
  163 + s->pull[0] = 0x00;
  164 + s->pull[1] = 0x00;
  165 + s->pull[2] = 0x00;
  166 + s->pull[3] = 0x00;
  167 + s->mmc_ctrl[0] = 0x03;
  168 + s->mmc_ctrl[1] = 0xc0;
  169 + s->mmc_ctrl[2] = 0x00;
  170 + s->mmc_debounce = 0x05;
  171 +
  172 + time(&ti);
  173 + if (s->rtc.ctrl & 1)
  174 + menelaus_rtc_stop(s);
  175 + s->rtc.ctrl = 0x00;
  176 + s->rtc.comp = 0x0000;
  177 + s->rtc.next = 1000;
  178 + s->rtc.sec = ti;
  179 + s->rtc.next_comp = s->rtc.sec + 1800;
  180 + s->rtc.alm.tm_sec = 0x00;
  181 + s->rtc.alm.tm_min = 0x00;
  182 + s->rtc.alm.tm_hour = 0x00;
  183 + s->rtc.alm.tm_mday = 0x01;
  184 + s->rtc.alm.tm_mon = 0x00;
  185 + s->rtc.alm.tm_year = 2004;
  186 + menelaus_update(s);
  187 +}
  188 +
  189 +static inline uint8_t to_bcd(int val)
  190 +{
  191 + return ((val / 10) << 4) | (val % 10);
  192 +}
  193 +
  194 +static inline int from_bcd(uint8_t val)
  195 +{
  196 + return ((val >> 4) * 10) + (val & 0x0f);
  197 +}
  198 +
  199 +static void menelaus_gpio_set(void *opaque, int line, int level)
  200 +{
  201 + struct menelaus_s *s = (struct menelaus_s *) opaque;
  202 +
  203 + /* No interrupt generated */
  204 + s->inputs &= ~(1 << line);
  205 + s->inputs |= level << line;
  206 +}
  207 +
  208 +static void menelaus_pwrbtn_set(void *opaque, int line, int level)
  209 +{
  210 + struct menelaus_s *s = (struct menelaus_s *) opaque;
  211 +
  212 + if (!s->pwrbtn_state && level) {
  213 + s->status |= 1 << 11; /* PSHBTN */
  214 + menelaus_update(s);
  215 + }
  216 + s->pwrbtn_state = level;
  217 +}
  218 +
  219 +#define MENELAUS_REV 0x01
  220 +#define MENELAUS_VCORE_CTRL1 0x02
  221 +#define MENELAUS_VCORE_CTRL2 0x03
  222 +#define MENELAUS_VCORE_CTRL3 0x04
  223 +#define MENELAUS_VCORE_CTRL4 0x05
  224 +#define MENELAUS_VCORE_CTRL5 0x06
  225 +#define MENELAUS_DCDC_CTRL1 0x07
  226 +#define MENELAUS_DCDC_CTRL2 0x08
  227 +#define MENELAUS_DCDC_CTRL3 0x09
  228 +#define MENELAUS_LDO_CTRL1 0x0a
  229 +#define MENELAUS_LDO_CTRL2 0x0b
  230 +#define MENELAUS_LDO_CTRL3 0x0c
  231 +#define MENELAUS_LDO_CTRL4 0x0d
  232 +#define MENELAUS_LDO_CTRL5 0x0e
  233 +#define MENELAUS_LDO_CTRL6 0x0f
  234 +#define MENELAUS_LDO_CTRL7 0x10
  235 +#define MENELAUS_LDO_CTRL8 0x11
  236 +#define MENELAUS_SLEEP_CTRL1 0x12
  237 +#define MENELAUS_SLEEP_CTRL2 0x13
  238 +#define MENELAUS_DEVICE_OFF 0x14
  239 +#define MENELAUS_OSC_CTRL 0x15
  240 +#define MENELAUS_DETECT_CTRL 0x16
  241 +#define MENELAUS_INT_MASK1 0x17
  242 +#define MENELAUS_INT_MASK2 0x18
  243 +#define MENELAUS_INT_STATUS1 0x19
  244 +#define MENELAUS_INT_STATUS2 0x1a
  245 +#define MENELAUS_INT_ACK1 0x1b
  246 +#define MENELAUS_INT_ACK2 0x1c
  247 +#define MENELAUS_GPIO_CTRL 0x1d
  248 +#define MENELAUS_GPIO_IN 0x1e
  249 +#define MENELAUS_GPIO_OUT 0x1f
  250 +#define MENELAUS_BBSMS 0x20
  251 +#define MENELAUS_RTC_CTRL 0x21
  252 +#define MENELAUS_RTC_UPDATE 0x22
  253 +#define MENELAUS_RTC_SEC 0x23
  254 +#define MENELAUS_RTC_MIN 0x24
  255 +#define MENELAUS_RTC_HR 0x25
  256 +#define MENELAUS_RTC_DAY 0x26
  257 +#define MENELAUS_RTC_MON 0x27
  258 +#define MENELAUS_RTC_YR 0x28
  259 +#define MENELAUS_RTC_WKDAY 0x29
  260 +#define MENELAUS_RTC_AL_SEC 0x2a
  261 +#define MENELAUS_RTC_AL_MIN 0x2b
  262 +#define MENELAUS_RTC_AL_HR 0x2c
  263 +#define MENELAUS_RTC_AL_DAY 0x2d
  264 +#define MENELAUS_RTC_AL_MON 0x2e
  265 +#define MENELAUS_RTC_AL_YR 0x2f
  266 +#define MENELAUS_RTC_COMP_MSB 0x30
  267 +#define MENELAUS_RTC_COMP_LSB 0x31
  268 +#define MENELAUS_S1_PULL_EN 0x32
  269 +#define MENELAUS_S1_PULL_DIR 0x33
  270 +#define MENELAUS_S2_PULL_EN 0x34
  271 +#define MENELAUS_S2_PULL_DIR 0x35
  272 +#define MENELAUS_MCT_CTRL1 0x36
  273 +#define MENELAUS_MCT_CTRL2 0x37
  274 +#define MENELAUS_MCT_CTRL3 0x38
  275 +#define MENELAUS_MCT_PIN_ST 0x39
  276 +#define MENELAUS_DEBOUNCE1 0x3a
  277 +
  278 +static uint8_t menelaus_read(void *opaque, uint8_t addr)
  279 +{
  280 + struct menelaus_s *s = (struct menelaus_s *) opaque;
  281 + int reg = 0;
  282 +
  283 + switch (addr) {
  284 + case MENELAUS_REV:
  285 + return 0x22;
  286 +
  287 + case MENELAUS_VCORE_CTRL5: reg ++;
  288 + case MENELAUS_VCORE_CTRL4: reg ++;
  289 + case MENELAUS_VCORE_CTRL3: reg ++;
  290 + case MENELAUS_VCORE_CTRL2: reg ++;
  291 + case MENELAUS_VCORE_CTRL1:
  292 + return s->vcore[reg];
  293 +
  294 + case MENELAUS_DCDC_CTRL3: reg ++;
  295 + case MENELAUS_DCDC_CTRL2: reg ++;
  296 + case MENELAUS_DCDC_CTRL1:
  297 + return s->dcdc[reg];
  298 +
  299 + case MENELAUS_LDO_CTRL8: reg ++;
  300 + case MENELAUS_LDO_CTRL7: reg ++;
  301 + case MENELAUS_LDO_CTRL6: reg ++;
  302 + case MENELAUS_LDO_CTRL5: reg ++;
  303 + case MENELAUS_LDO_CTRL4: reg ++;
  304 + case MENELAUS_LDO_CTRL3: reg ++;
  305 + case MENELAUS_LDO_CTRL2: reg ++;
  306 + case MENELAUS_LDO_CTRL1:
  307 + return s->ldo[reg];
  308 +
  309 + case MENELAUS_SLEEP_CTRL2: reg ++;
  310 + case MENELAUS_SLEEP_CTRL1:
  311 + return s->sleep[reg];
  312 +
  313 + case MENELAUS_DEVICE_OFF:
  314 + return 0;
  315 +
  316 + case MENELAUS_OSC_CTRL:
  317 + return s->osc | (1 << 7); /* CLK32K_GOOD */
  318 +
  319 + case MENELAUS_DETECT_CTRL:
  320 + return s->detect;
  321 +
  322 + case MENELAUS_INT_MASK1:
  323 + return (s->mask >> 0) & 0xff;
  324 + case MENELAUS_INT_MASK2:
  325 + return (s->mask >> 8) & 0xff;
  326 +
  327 + case MENELAUS_INT_STATUS1:
  328 + return (s->status >> 0) & 0xff;
  329 + case MENELAUS_INT_STATUS2:
  330 + return (s->status >> 8) & 0xff;
  331 +
  332 + case MENELAUS_INT_ACK1:
  333 + case MENELAUS_INT_ACK2:
  334 + return 0;
  335 +
  336 + case MENELAUS_GPIO_CTRL:
  337 + return s->dir;
  338 + case MENELAUS_GPIO_IN:
  339 + return s->inputs | (~s->dir & s->outputs);
  340 + case MENELAUS_GPIO_OUT:
  341 + return s->outputs;
  342 +
  343 + case MENELAUS_BBSMS:
  344 + return s->bbsms;
  345 +
  346 + case MENELAUS_RTC_CTRL:
  347 + return s->rtc.ctrl;
  348 + case MENELAUS_RTC_UPDATE:
  349 + return 0x00;
  350 + case MENELAUS_RTC_SEC:
  351 + menelaus_rtc_update(s);
  352 + return to_bcd(s->rtc.tm.tm_sec);
  353 + case MENELAUS_RTC_MIN:
  354 + menelaus_rtc_update(s);
  355 + return to_bcd(s->rtc.tm.tm_min);
  356 + case MENELAUS_RTC_HR:
  357 + menelaus_rtc_update(s);
  358 + if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
  359 + return to_bcd((s->rtc.tm.tm_hour % 12) + 1) |
  360 + (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */
  361 + else
  362 + return to_bcd(s->rtc.tm.tm_hour);
  363 + case MENELAUS_RTC_DAY:
  364 + menelaus_rtc_update(s);
  365 + return to_bcd(s->rtc.tm.tm_mday);
  366 + case MENELAUS_RTC_MON:
  367 + menelaus_rtc_update(s);
  368 + return to_bcd(s->rtc.tm.tm_mon + 1);
  369 + case MENELAUS_RTC_YR:
  370 + menelaus_rtc_update(s);
  371 + return to_bcd(s->rtc.tm.tm_year - 2000);
  372 + case MENELAUS_RTC_WKDAY:
  373 + menelaus_rtc_update(s);
  374 + return to_bcd(s->rtc.tm.tm_wday);
  375 + case MENELAUS_RTC_AL_SEC:
  376 + return to_bcd(s->rtc.alm.tm_sec);
  377 + case MENELAUS_RTC_AL_MIN:
  378 + return to_bcd(s->rtc.alm.tm_min);
  379 + case MENELAUS_RTC_AL_HR:
  380 + if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
  381 + return to_bcd((s->rtc.alm.tm_hour % 12) + 1) |
  382 + (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */
  383 + else
  384 + return to_bcd(s->rtc.alm.tm_hour);
  385 + case MENELAUS_RTC_AL_DAY:
  386 + return to_bcd(s->rtc.alm.tm_mday);
  387 + case MENELAUS_RTC_AL_MON:
  388 + return to_bcd(s->rtc.alm.tm_mon + 1);
  389 + case MENELAUS_RTC_AL_YR:
  390 + return to_bcd(s->rtc.alm.tm_year - 2000);
  391 + case MENELAUS_RTC_COMP_MSB:
  392 + return (s->rtc.comp >> 8) & 0xff;
  393 + case MENELAUS_RTC_COMP_LSB:
  394 + return (s->rtc.comp >> 0) & 0xff;
  395 +
  396 + case MENELAUS_S1_PULL_EN:
  397 + return s->pull[0];
  398 + case MENELAUS_S1_PULL_DIR:
  399 + return s->pull[1];
  400 + case MENELAUS_S2_PULL_EN:
  401 + return s->pull[2];
  402 + case MENELAUS_S2_PULL_DIR:
  403 + return s->pull[3];
  404 +
  405 + case MENELAUS_MCT_CTRL3: reg ++;
  406 + case MENELAUS_MCT_CTRL2: reg ++;
  407 + case MENELAUS_MCT_CTRL1:
  408 + return s->mmc_ctrl[reg];
  409 + case MENELAUS_MCT_PIN_ST:
  410 + /* TODO: return the real Card Detect */
  411 + return 0;
  412 + case MENELAUS_DEBOUNCE1:
  413 + return s->mmc_debounce;
  414 +
  415 + default:
  416 +#ifdef VERBOSE
  417 + printf("%s: unknown register %02x\n", __FUNCTION__, addr);
  418 +#endif
  419 + break;
  420 + }
  421 + return 0;
  422 +}
  423 +
  424 +static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
  425 +{
  426 + struct menelaus_s *s = (struct menelaus_s *) opaque;
  427 + int line;
  428 + int reg = 0;
  429 + struct tm tm;
  430 +
  431 + switch (addr) {
  432 + case MENELAUS_VCORE_CTRL1:
  433 + s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
  434 + break;
  435 + case MENELAUS_VCORE_CTRL2:
  436 + s->vcore[1] = value;
  437 + break;
  438 + case MENELAUS_VCORE_CTRL3:
  439 + s->vcore[2] = MIN(value & 0x1f, 0x12);
  440 + break;
  441 + case MENELAUS_VCORE_CTRL4:
  442 + s->vcore[3] = MIN(value & 0x1f, 0x12);
  443 + break;
  444 + case MENELAUS_VCORE_CTRL5:
  445 + s->vcore[4] = value & 3;
  446 + /* XXX
  447 + * auto set to 3 on M_Active, nRESWARM
  448 + * auto set to 0 on M_WaitOn, M_Backup
  449 + */
  450 + break;
  451 +
  452 + case MENELAUS_DCDC_CTRL1:
  453 + s->dcdc[0] = value & 0x3f;
  454 + break;
  455 + case MENELAUS_DCDC_CTRL2:
  456 + s->dcdc[1] = value & 0x07;
  457 + /* XXX
  458 + * auto set to 3 on M_Active, nRESWARM
  459 + * auto set to 0 on M_WaitOn, M_Backup
  460 + */
  461 + break;
  462 + case MENELAUS_DCDC_CTRL3:
  463 + s->dcdc[2] = value & 0x07;
  464 + break;
  465 +
  466 + case MENELAUS_LDO_CTRL1:
  467 + s->ldo[0] = value;
  468 + break;
  469 + case MENELAUS_LDO_CTRL2:
  470 + s->ldo[1] = value & 0x7f;
  471 + /* XXX
  472 + * auto set to 0x7e on M_WaitOn, M_Backup
  473 + */
  474 + break;
  475 + case MENELAUS_LDO_CTRL3:
  476 + s->ldo[2] = value & 3;
  477 + /* XXX
  478 + * auto set to 3 on M_Active, nRESWARM
  479 + * auto set to 0 on M_WaitOn, M_Backup
  480 + */
  481 + break;
  482 + case MENELAUS_LDO_CTRL4:
  483 + s->ldo[3] = value & 3;
  484 + /* XXX
  485 + * auto set to 3 on M_Active, nRESWARM
  486 + * auto set to 0 on M_WaitOn, M_Backup
  487 + */
  488 + break;
  489 + case MENELAUS_LDO_CTRL5:
  490 + s->ldo[4] = value & 3;
  491 + /* XXX
  492 + * auto set to 3 on M_Active, nRESWARM
  493 + * auto set to 0 on M_WaitOn, M_Backup
  494 + */
  495 + break;
  496 + case MENELAUS_LDO_CTRL6:
  497 + s->ldo[5] = value & 3;
  498 + break;
  499 + case MENELAUS_LDO_CTRL7:
  500 + s->ldo[6] = value & 3;
  501 + break;
  502 + case MENELAUS_LDO_CTRL8:
  503 + s->ldo[7] = value & 3;
  504 + break;
  505 +
  506 + case MENELAUS_SLEEP_CTRL2: reg ++;
  507 + case MENELAUS_SLEEP_CTRL1:
  508 + s->sleep[reg] = value;
  509 + break;
  510 +
  511 + case MENELAUS_DEVICE_OFF:
  512 + if (value & 1)
  513 + menelaus_reset(&s->i2c);
  514 + break;
  515 +
  516 + case MENELAUS_OSC_CTRL:
  517 + s->osc = value & 7;
  518 + break;
  519 +
  520 + case MENELAUS_DETECT_CTRL:
  521 + s->detect = value & 0x7f;
  522 + break;
  523 +
  524 + case MENELAUS_INT_MASK1:
  525 + s->mask &= 0xf00;
  526 + s->mask |= value << 0;
  527 + menelaus_update(s);
  528 + break;
  529 + case MENELAUS_INT_MASK2:
  530 + s->mask &= 0x0ff;
  531 + s->mask |= value << 8;
  532 + menelaus_update(s);
  533 + break;
  534 +
  535 + case MENELAUS_INT_ACK1:
  536 + s->status &= ~(((uint16_t) value) << 0);
  537 + menelaus_update(s);
  538 + break;
  539 + case MENELAUS_INT_ACK2:
  540 + s->status &= ~(((uint16_t) value) << 8);
  541 + menelaus_update(s);
  542 + break;
  543 +
  544 + case MENELAUS_GPIO_CTRL:
  545 + for (line = 0; line < 3; line ++)
  546 + if (((s->dir ^ value) >> line) & 1)
  547 + if (s->handler[line])
  548 + qemu_set_irq(s->handler[line],
  549 + ((s->outputs & ~s->dir) >> line) & 1);
  550 + s->dir = value & 0x67;
  551 + break;
  552 + case MENELAUS_GPIO_OUT:
  553 + for (line = 0; line < 3; line ++)
  554 + if ((((s->outputs ^ value) & ~s->dir) >> line) & 1)
  555 + if (s->handler[line])
  556 + qemu_set_irq(s->handler[line], (s->outputs >> line) & 1);
  557 + s->outputs = value & 0x07;
  558 + break;
  559 +
  560 + case MENELAUS_BBSMS:
  561 + s->bbsms = 0x0d;
  562 + break;
  563 +
  564 + case MENELAUS_RTC_CTRL:
  565 + if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */
  566 + if (value & 1)
  567 + menelaus_rtc_start(s);
  568 + else
  569 + menelaus_rtc_stop(s);
  570 + }
  571 + s->rtc.ctrl = value & 0x1f;
  572 + menelaus_alm_update(s);
  573 + break;
  574 + case MENELAUS_RTC_UPDATE:
  575 + menelaus_rtc_update(s);
  576 + memcpy(&tm, &s->rtc.tm, sizeof(tm));
  577 + switch (value & 0xf) {
  578 + case 0:
  579 + break;
  580 + case 1:
  581 + tm.tm_sec = s->rtc.new.tm_sec;
  582 + break;
  583 + case 2:
  584 + tm.tm_min = s->rtc.new.tm_min;
  585 + break;
  586 + case 3:
  587 + if (s->rtc.new.tm_hour > 23)
  588 + goto rtc_badness;
  589 + tm.tm_hour = s->rtc.new.tm_hour;
  590 + break;
  591 + case 4:
  592 + if (s->rtc.new.tm_mday < 1)
  593 + goto rtc_badness;
  594 + /* TODO check range */
  595 + tm.tm_mday = s->rtc.new.tm_mday;
  596 + break;
  597 + case 5:
  598 + if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
  599 + goto rtc_badness;
  600 + tm.tm_mon = s->rtc.new.tm_mon;
  601 + break;
  602 + case 6:
  603 + tm.tm_year = s->rtc.new.tm_year;
  604 + break;
  605 + case 7:
  606 + /* TODO set .tm_mday instead */
  607 + tm.tm_wday = s->rtc.new.tm_wday;
  608 + break;
  609 + case 8:
  610 + if (s->rtc.new.tm_hour > 23)
  611 + goto rtc_badness;
  612 + if (s->rtc.new.tm_mday < 1)
  613 + goto rtc_badness;
  614 + if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
  615 + goto rtc_badness;
  616 + tm.tm_sec = s->rtc.new.tm_sec;
  617 + tm.tm_min = s->rtc.new.tm_min;
  618 + tm.tm_hour = s->rtc.new.tm_hour;
  619 + tm.tm_mday = s->rtc.new.tm_mday;
  620 + tm.tm_mon = s->rtc.new.tm_mon;
  621 + tm.tm_year = s->rtc.new.tm_year;
  622 + break;
  623 + rtc_badness:
  624 + default:
  625 + fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
  626 + __FUNCTION__, value);
  627 + s->status |= 1 << 10; /* RTCERR */
  628 + menelaus_update(s);
  629 + }
  630 + s->rtc.sec += difftime(mktime(&tm), mktime(&s->rtc.tm));
  631 + break;
  632 + case MENELAUS_RTC_SEC:
  633 + s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
  634 + break;
  635 + case MENELAUS_RTC_MIN:
  636 + s->rtc.tm.tm_min = from_bcd(value & 0x7f);
  637 + break;
  638 + case MENELAUS_RTC_HR:
  639 + s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
  640 + MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
  641 + from_bcd(value & 0x3f);
  642 + break;
  643 + case MENELAUS_RTC_DAY:
  644 + s->rtc.tm.tm_mday = from_bcd(value);
  645 + break;
  646 + case MENELAUS_RTC_MON:
  647 + s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
  648 + break;
  649 + case MENELAUS_RTC_YR:
  650 + s->rtc.tm.tm_year = 2000 + from_bcd(value);
  651 + break;
  652 + case MENELAUS_RTC_WKDAY:
  653 + s->rtc.tm.tm_mday = from_bcd(value);
  654 + break;
  655 + case MENELAUS_RTC_AL_SEC:
  656 + s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
  657 + menelaus_alm_update(s);
  658 + break;
  659 + case MENELAUS_RTC_AL_MIN:
  660 + s->rtc.alm.tm_min = from_bcd(value & 0x7f);
  661 + menelaus_alm_update(s);
  662 + break;
  663 + case MENELAUS_RTC_AL_HR:
  664 + s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
  665 + MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
  666 + from_bcd(value & 0x3f);
  667 + menelaus_alm_update(s);
  668 + break;
  669 + case MENELAUS_RTC_AL_DAY:
  670 + s->rtc.alm.tm_mday = from_bcd(value);
  671 + menelaus_alm_update(s);
  672 + break;
  673 + case MENELAUS_RTC_AL_MON:
  674 + s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
  675 + menelaus_alm_update(s);
  676 + break;
  677 + case MENELAUS_RTC_AL_YR:
  678 + s->rtc.alm.tm_year = 2000 + from_bcd(value);
  679 + menelaus_alm_update(s);
  680 + break;
  681 + case MENELAUS_RTC_COMP_MSB:
  682 + s->rtc.comp &= 0xff;
  683 + s->rtc.comp |= value << 8;
  684 + break;
  685 + case MENELAUS_RTC_COMP_LSB:
  686 + s->rtc.comp &= 0xff << 8;
  687 + s->rtc.comp |= value;
  688 + break;
  689 +
  690 + case MENELAUS_S1_PULL_EN:
  691 + s->pull[0] = value;
  692 + break;
  693 + case MENELAUS_S1_PULL_DIR:
  694 + s->pull[1] = value & 0x1f;
  695 + break;
  696 + case MENELAUS_S2_PULL_EN:
  697 + s->pull[2] = value;
  698 + break;
  699 + case MENELAUS_S2_PULL_DIR:
  700 + s->pull[3] = value & 0x1f;
  701 + break;
  702 +
  703 + case MENELAUS_MCT_CTRL1:
  704 + s->mmc_ctrl[0] = value & 0x7f;
  705 + break;
  706 + case MENELAUS_MCT_CTRL2:
  707 + s->mmc_ctrl[1] = value;
  708 + /* TODO update Card Detect interrupts */
  709 + break;
  710 + case MENELAUS_MCT_CTRL3:
  711 + s->mmc_ctrl[2] = value & 0xf;
  712 + break;
  713 + case MENELAUS_DEBOUNCE1:
  714 + s->mmc_debounce = value & 0x3f;
  715 + break;
  716 +
  717 + default:
  718 +#ifdef VERBOSE
  719 + printf("%s: unknown register %02x\n", __FUNCTION__, addr);
  720 +#endif
  721 + }
  722 +}
  723 +
  724 +static void menelaus_event(i2c_slave *i2c, enum i2c_event event)
  725 +{
  726 + struct menelaus_s *s = (struct menelaus_s *) i2c;
  727 +
  728 + if (event == I2C_START_SEND)
  729 + s->firstbyte = 1;
  730 +}
  731 +
  732 +static int menelaus_tx(i2c_slave *i2c, uint8_t data)
  733 +{
  734 + struct menelaus_s *s = (struct menelaus_s *) i2c;
  735 + /* Interpret register address byte */
  736 + if (s->firstbyte) {
  737 + s->reg = data;
  738 + s->firstbyte = 0;
  739 + } else
  740 + menelaus_write(s, s->reg ++, data);
  741 +
  742 + return 0;
  743 +}
  744 +
  745 +static int menelaus_rx(i2c_slave *i2c)
  746 +{
  747 + struct menelaus_s *s = (struct menelaus_s *) i2c;
  748 +
  749 + return menelaus_read(s, s->reg ++);
  750 +}
  751 +
  752 +static void tm_put(QEMUFile *f, struct tm *tm) {
  753 + qemu_put_be16(f, tm->tm_sec);
  754 + qemu_put_be16(f, tm->tm_min);
  755 + qemu_put_be16(f, tm->tm_hour);
  756 + qemu_put_be16(f, tm->tm_mday);
  757 + qemu_put_be16(f, tm->tm_min);
  758 + qemu_put_be16(f, tm->tm_year);
  759 +}
  760 +
  761 +static void tm_get(QEMUFile *f, struct tm *tm) {
  762 + tm->tm_sec = qemu_get_be16(f);
  763 + tm->tm_min = qemu_get_be16(f);
  764 + tm->tm_hour = qemu_get_be16(f);
  765 + tm->tm_mday = qemu_get_be16(f);
  766 + tm->tm_min = qemu_get_be16(f);
  767 + tm->tm_year = qemu_get_be16(f);
  768 +}
  769 +
  770 +static void menelaus_save(QEMUFile *f, void *opaque)
  771 +{
  772 + struct menelaus_s *s = (struct menelaus_s *) opaque;
  773 +
  774 + qemu_put_be32(f, s->firstbyte);
  775 + qemu_put_8s(f, &s->reg);
  776 +
  777 + qemu_put_8s(f, &s->vcore[0]);
  778 + qemu_put_8s(f, &s->vcore[1]);
  779 + qemu_put_8s(f, &s->vcore[2]);
  780 + qemu_put_8s(f, &s->vcore[3]);
  781 + qemu_put_8s(f, &s->vcore[4]);
  782 + qemu_put_8s(f, &s->dcdc[3]);
  783 + qemu_put_8s(f, &s->dcdc[3]);
  784 + qemu_put_8s(f, &s->dcdc[3]);
  785 + qemu_put_8s(f, &s->ldo[0]);
  786 + qemu_put_8s(f, &s->ldo[1]);
  787 + qemu_put_8s(f, &s->ldo[2]);
  788 + qemu_put_8s(f, &s->ldo[3]);
  789 + qemu_put_8s(f, &s->ldo[4]);
  790 + qemu_put_8s(f, &s->ldo[5]);
  791 + qemu_put_8s(f, &s->ldo[6]);
  792 + qemu_put_8s(f, &s->ldo[7]);
  793 + qemu_put_8s(f, &s->sleep[0]);
  794 + qemu_put_8s(f, &s->sleep[1]);
  795 + qemu_put_8s(f, &s->osc);
  796 + qemu_put_8s(f, &s->detect);
  797 + qemu_put_be16s(f, &s->mask);
  798 + qemu_put_be16s(f, &s->status);
  799 + qemu_put_8s(f, &s->dir);
  800 + qemu_put_8s(f, &s->inputs);
  801 + qemu_put_8s(f, &s->outputs);
  802 + qemu_put_8s(f, &s->bbsms);
  803 + qemu_put_8s(f, &s->pull[0]);
  804 + qemu_put_8s(f, &s->pull[1]);
  805 + qemu_put_8s(f, &s->pull[2]);
  806 + qemu_put_8s(f, &s->pull[3]);
  807 + qemu_put_8s(f, &s->mmc_ctrl[0]);
  808 + qemu_put_8s(f, &s->mmc_ctrl[1]);
  809 + qemu_put_8s(f, &s->mmc_ctrl[2]);
  810 + qemu_put_8s(f, &s->mmc_debounce);
  811 + qemu_put_8s(f, &s->rtc.ctrl);
  812 + qemu_put_be16s(f, &s->rtc.comp);
  813 + /* Should be <= 1000 */
  814 + qemu_put_be16(f, s->rtc.next - qemu_get_clock(rt_clock));
  815 + tm_put(f, &s->rtc.new);
  816 + tm_put(f, &s->rtc.alm);
  817 + qemu_put_byte(f, s->pwrbtn_state);
  818 +
  819 + i2c_slave_save(f, &s->i2c);
  820 +}
  821 +
  822 +static int menelaus_load(QEMUFile *f, void *opaque, int version_id)
  823 +{
  824 + struct menelaus_s *s = (struct menelaus_s *) opaque;
  825 +
  826 + s->firstbyte = qemu_get_be32(f);
  827 + qemu_get_8s(f, &s->reg);
  828 +
  829 + if (s->rtc.ctrl & 1) /* RTC_EN */
  830 + menelaus_rtc_stop(s);
  831 + qemu_get_8s(f, &s->vcore[0]);
  832 + qemu_get_8s(f, &s->vcore[1]);
  833 + qemu_get_8s(f, &s->vcore[2]);
  834 + qemu_get_8s(f, &s->vcore[3]);
  835 + qemu_get_8s(f, &s->vcore[4]);
  836 + qemu_get_8s(f, &s->dcdc[3]);
  837 + qemu_get_8s(f, &s->dcdc[3]);
  838 + qemu_get_8s(f, &s->dcdc[3]);
  839 + qemu_get_8s(f, &s->ldo[0]);
  840 + qemu_get_8s(f, &s->ldo[1]);
  841 + qemu_get_8s(f, &s->ldo[2]);
  842 + qemu_get_8s(f, &s->ldo[3]);
  843 + qemu_get_8s(f, &s->ldo[4]);
  844 + qemu_get_8s(f, &s->ldo[5]);
  845 + qemu_get_8s(f, &s->ldo[6]);
  846 + qemu_get_8s(f, &s->ldo[7]);
  847 + qemu_get_8s(f, &s->sleep[0]);
  848 + qemu_get_8s(f, &s->sleep[1]);
  849 + qemu_get_8s(f, &s->osc);
  850 + qemu_get_8s(f, &s->detect);
  851 + qemu_get_be16s(f, &s->mask);
  852 + qemu_get_be16s(f, &s->status);
  853 + qemu_get_8s(f, &s->dir);
  854 + qemu_get_8s(f, &s->inputs);
  855 + qemu_get_8s(f, &s->outputs);
  856 + qemu_get_8s(f, &s->bbsms);
  857 + qemu_get_8s(f, &s->pull[0]);
  858 + qemu_get_8s(f, &s->pull[1]);
  859 + qemu_get_8s(f, &s->pull[2]);
  860 + qemu_get_8s(f, &s->pull[3]);
  861 + qemu_get_8s(f, &s->mmc_ctrl[0]);
  862 + qemu_get_8s(f, &s->mmc_ctrl[1]);
  863 + qemu_get_8s(f, &s->mmc_ctrl[2]);
  864 + qemu_get_8s(f, &s->mmc_debounce);
  865 + qemu_get_8s(f, &s->rtc.ctrl);
  866 + qemu_get_be16s(f, &s->rtc.comp);
  867 + s->rtc.next = qemu_get_be16(f);
  868 + tm_get(f, &s->rtc.new);
  869 + tm_get(f, &s->rtc.alm);
  870 + s->pwrbtn_state = qemu_get_byte(f);
  871 + menelaus_alm_update(s);
  872 + menelaus_update(s);
  873 + if (s->rtc.ctrl & 1) /* RTC_EN */
  874 + menelaus_rtc_start(s);
  875 +
  876 + i2c_slave_load(f, &s->i2c);
  877 + return 0;
  878 +}
  879 +
  880 +static int menelaus_iid = 0;
  881 +
  882 +i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq)
  883 +{
  884 + struct menelaus_s *s = (struct menelaus_s *)
  885 + i2c_slave_init(bus, 0, sizeof(struct menelaus_s));
  886 +
  887 + s->i2c.event = menelaus_event;
  888 + s->i2c.recv = menelaus_rx;
  889 + s->i2c.send = menelaus_tx;
  890 +
  891 + /* TODO: use the qemu gettime functions */
  892 + s->rtc.gettime = localtime_r;
  893 +
  894 + s->irq = irq;
  895 + s->rtc.hz = qemu_new_timer(rt_clock, menelaus_rtc_hz, s);
  896 + s->in = qemu_allocate_irqs(menelaus_gpio_set, s, 3);
  897 + s->pwrbtn = qemu_allocate_irqs(menelaus_pwrbtn_set, s, 1)[0];
  898 +
  899 + menelaus_reset(&s->i2c);
  900 +
  901 + register_savevm("menelaus", menelaus_iid ++,
  902 + 0, menelaus_save, menelaus_load, s);
  903 +
  904 + return &s->i2c;
  905 +}
  906 +
  907 +qemu_irq *twl92230_gpio_in_get(i2c_slave *i2c)
  908 +{
  909 + struct menelaus_s *s = (struct menelaus_s *) i2c;
  910 +
  911 + return s->in;
  912 +}
  913 +
  914 +void twl92230_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler)
  915 +{
  916 + struct menelaus_s *s = (struct menelaus_s *) i2c;
  917 +
  918 + if (line >= 3 || line < 0) {
  919 + fprintf(stderr, "%s: No GPO line %i\n", __FUNCTION__, line);
  920 + exit(-1);
  921 + }
  922 + s->handler[line] = handler;
  923 +}
... ...
... ... @@ -8051,6 +8051,7 @@ static void register_machines(void)
8051 8051 qemu_register_machine(&borzoipda_machine);
8052 8052 qemu_register_machine(&terrierpda_machine);
8053 8053 qemu_register_machine(&palmte_machine);
  8054 + qemu_register_machine(&n800_machine);
8054 8055 qemu_register_machine(&lm3s811evb_machine);
8055 8056 qemu_register_machine(&lm3s6965evb_machine);
8056 8057 qemu_register_machine(&connex_machine);
... ...