balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2006-2008 Openedhand Ltd. |
| 3 | * Written by Andrzej Zaborowski <balrog@zabor.org> |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU General Public License as |
| 7 | * published by the Free Software Foundation; either version 2 or |
| 8 | * (at your option) version 3 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
aurel32 | fad6cb1 | 2009-01-04 22:05:52 +0000 | [diff] [blame] | 15 | * You should have received a copy of the GNU General Public License along |
Blue Swirl | 8167ee8 | 2009-07-16 20:47:01 +0000 | [diff] [blame] | 16 | * with this program; if not, see <http://www.gnu.org/licenses/>. |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 17 | */ |
| 18 | #include "hw.h" |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 19 | #include "sharpsl.h" |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 20 | #include "sysbus.h" |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 21 | |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 22 | #undef REG_FMT |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 23 | #define REG_FMT "0x%02lx" |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 24 | |
| 25 | /* SCOOP devices */ |
| 26 | |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 27 | typedef struct ScoopInfo ScoopInfo; |
Paul Brook | bc24a22 | 2009-05-10 01:44:56 +0100 | [diff] [blame] | 28 | struct ScoopInfo { |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 29 | SysBusDevice busdev; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 30 | qemu_irq handler[16]; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 31 | uint16_t status; |
| 32 | uint16_t power; |
| 33 | uint32_t gpio_level; |
| 34 | uint32_t gpio_dir; |
| 35 | uint32_t prev_level; |
| 36 | |
| 37 | uint16_t mcr; |
| 38 | uint16_t cdr; |
| 39 | uint16_t ccr; |
| 40 | uint16_t irr; |
| 41 | uint16_t imr; |
| 42 | uint16_t isr; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 43 | }; |
| 44 | |
| 45 | #define SCOOP_MCR 0x00 |
| 46 | #define SCOOP_CDR 0x04 |
| 47 | #define SCOOP_CSR 0x08 |
| 48 | #define SCOOP_CPR 0x0c |
| 49 | #define SCOOP_CCR 0x10 |
| 50 | #define SCOOP_IRR_IRM 0x14 |
| 51 | #define SCOOP_IMR 0x18 |
| 52 | #define SCOOP_ISR 0x1c |
| 53 | #define SCOOP_GPCR 0x20 |
| 54 | #define SCOOP_GPWR 0x24 |
| 55 | #define SCOOP_GPRR 0x28 |
| 56 | |
Paul Brook | bc24a22 | 2009-05-10 01:44:56 +0100 | [diff] [blame] | 57 | static inline void scoop_gpio_handler_update(ScoopInfo *s) { |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 58 | uint32_t level, diff; |
| 59 | int bit; |
| 60 | level = s->gpio_level & s->gpio_dir; |
| 61 | |
| 62 | for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { |
| 63 | bit = ffs(diff) - 1; |
| 64 | qemu_set_irq(s->handler[bit], (level >> bit) & 1); |
| 65 | } |
| 66 | |
| 67 | s->prev_level = level; |
| 68 | } |
| 69 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 70 | static uint32_t scoop_readb(void *opaque, target_phys_addr_t addr) |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 71 | { |
Paul Brook | bc24a22 | 2009-05-10 01:44:56 +0100 | [diff] [blame] | 72 | ScoopInfo *s = (ScoopInfo *) opaque; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 73 | |
Dmitry Eremin-Solenikov | aa9438d | 2011-01-13 18:37:11 +0300 | [diff] [blame] | 74 | switch (addr & 0x3f) { |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 75 | case SCOOP_MCR: |
| 76 | return s->mcr; |
| 77 | case SCOOP_CDR: |
| 78 | return s->cdr; |
| 79 | case SCOOP_CSR: |
| 80 | return s->status; |
| 81 | case SCOOP_CPR: |
| 82 | return s->power; |
| 83 | case SCOOP_CCR: |
| 84 | return s->ccr; |
| 85 | case SCOOP_IRR_IRM: |
| 86 | return s->irr; |
| 87 | case SCOOP_IMR: |
| 88 | return s->imr; |
| 89 | case SCOOP_ISR: |
| 90 | return s->isr; |
| 91 | case SCOOP_GPCR: |
| 92 | return s->gpio_dir; |
| 93 | case SCOOP_GPWR: |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 94 | case SCOOP_GPRR: |
balrog | 1f163b1 | 2008-11-04 08:49:17 +0000 | [diff] [blame] | 95 | return s->gpio_level; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 96 | default: |
Blue Swirl | a8b7063 | 2009-06-13 15:08:49 +0000 | [diff] [blame] | 97 | zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | return 0; |
| 101 | } |
| 102 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 103 | static void scoop_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 104 | { |
Paul Brook | bc24a22 | 2009-05-10 01:44:56 +0100 | [diff] [blame] | 105 | ScoopInfo *s = (ScoopInfo *) opaque; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 106 | value &= 0xffff; |
| 107 | |
Dmitry Eremin-Solenikov | aa9438d | 2011-01-13 18:37:11 +0300 | [diff] [blame] | 108 | switch (addr & 0x3f) { |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 109 | case SCOOP_MCR: |
| 110 | s->mcr = value; |
| 111 | break; |
| 112 | case SCOOP_CDR: |
| 113 | s->cdr = value; |
| 114 | break; |
| 115 | case SCOOP_CPR: |
| 116 | s->power = value; |
| 117 | if (value & 0x80) |
| 118 | s->power |= 0x8040; |
| 119 | break; |
| 120 | case SCOOP_CCR: |
| 121 | s->ccr = value; |
| 122 | break; |
| 123 | case SCOOP_IRR_IRM: |
| 124 | s->irr = value; |
| 125 | break; |
| 126 | case SCOOP_IMR: |
| 127 | s->imr = value; |
| 128 | break; |
| 129 | case SCOOP_ISR: |
| 130 | s->isr = value; |
| 131 | break; |
| 132 | case SCOOP_GPCR: |
| 133 | s->gpio_dir = value; |
| 134 | scoop_gpio_handler_update(s); |
| 135 | break; |
| 136 | case SCOOP_GPWR: |
balrog | 1f163b1 | 2008-11-04 08:49:17 +0000 | [diff] [blame] | 137 | case SCOOP_GPRR: /* GPRR is probably R/O in real HW */ |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 138 | s->gpio_level = value & s->gpio_dir; |
| 139 | scoop_gpio_handler_update(s); |
| 140 | break; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 141 | default: |
Blue Swirl | a8b7063 | 2009-06-13 15:08:49 +0000 | [diff] [blame] | 142 | zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 143 | } |
| 144 | } |
| 145 | |
Blue Swirl | d60efc6 | 2009-08-25 18:29:31 +0000 | [diff] [blame] | 146 | static CPUReadMemoryFunc * const scoop_readfn[] = { |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 147 | scoop_readb, |
| 148 | scoop_readb, |
| 149 | scoop_readb, |
| 150 | }; |
Blue Swirl | d60efc6 | 2009-08-25 18:29:31 +0000 | [diff] [blame] | 151 | static CPUWriteMemoryFunc * const scoop_writefn[] = { |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 152 | scoop_writeb, |
| 153 | scoop_writeb, |
| 154 | scoop_writeb, |
| 155 | }; |
| 156 | |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 157 | static void scoop_gpio_set(void *opaque, int line, int level) |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 158 | { |
Torsten Duwe | 8d30b79 | 2009-08-23 18:08:14 +0200 | [diff] [blame] | 159 | ScoopInfo *s = (ScoopInfo *) opaque; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 160 | |
| 161 | if (level) |
| 162 | s->gpio_level |= (1 << line); |
| 163 | else |
| 164 | s->gpio_level &= ~(1 << line); |
| 165 | } |
| 166 | |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 167 | static int scoop_init(SysBusDevice *dev) |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 168 | { |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 169 | ScoopInfo *s = FROM_SYSBUS(ScoopInfo, dev); |
| 170 | int iomemtype; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 171 | |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 172 | s->status = 0x02; |
| 173 | qdev_init_gpio_out(&s->busdev.qdev, s->handler, 16); |
| 174 | qdev_init_gpio_in(&s->busdev.qdev, scoop_gpio_set, 16); |
| 175 | iomemtype = cpu_register_io_memory(scoop_readfn, |
| 176 | scoop_writefn, s, DEVICE_NATIVE_ENDIAN); |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 177 | |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 178 | sysbus_init_mmio(dev, 0x1000, iomemtype); |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 179 | |
| 180 | return 0; |
| 181 | } |
| 182 | |
Dmitry Eremin-Solenikov | 7fe63a1 | 2011-02-11 23:57:33 +0300 | [diff] [blame] | 183 | static int scoop_post_load(void *opaque, int version_id) |
| 184 | { |
| 185 | ScoopInfo *s = (ScoopInfo *) opaque; |
| 186 | int i; |
| 187 | uint32_t level; |
| 188 | |
| 189 | level = s->gpio_level & s->gpio_dir; |
| 190 | |
| 191 | for (i = 0; i < 16; i++) { |
| 192 | qemu_set_irq(s->handler[i], (level >> i) & 1); |
| 193 | } |
| 194 | |
| 195 | s->prev_level = level; |
| 196 | |
| 197 | return 0; |
| 198 | } |
| 199 | |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 200 | static bool is_version_0 (void *opaque, int version_id) |
| 201 | { |
| 202 | return version_id == 0; |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 203 | } |
| 204 | |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 205 | static const VMStateDescription vmstate_scoop_regs = { |
| 206 | .name = "scoop", |
| 207 | .version_id = 1, |
| 208 | .minimum_version_id = 0, |
| 209 | .minimum_version_id_old = 0, |
Dmitry Eremin-Solenikov | 7fe63a1 | 2011-02-11 23:57:33 +0300 | [diff] [blame] | 210 | .post_load = scoop_post_load, |
Dmitry Eremin-Solenikov | 383d01c | 2011-01-20 18:52:27 +0300 | [diff] [blame] | 211 | .fields = (VMStateField []) { |
| 212 | VMSTATE_UINT16(status, ScoopInfo), |
| 213 | VMSTATE_UINT16(power, ScoopInfo), |
| 214 | VMSTATE_UINT32(gpio_level, ScoopInfo), |
| 215 | VMSTATE_UINT32(gpio_dir, ScoopInfo), |
| 216 | VMSTATE_UINT32(prev_level, ScoopInfo), |
| 217 | VMSTATE_UINT16(mcr, ScoopInfo), |
| 218 | VMSTATE_UINT16(cdr, ScoopInfo), |
| 219 | VMSTATE_UINT16(ccr, ScoopInfo), |
| 220 | VMSTATE_UINT16(irr, ScoopInfo), |
| 221 | VMSTATE_UINT16(imr, ScoopInfo), |
| 222 | VMSTATE_UINT16(isr, ScoopInfo), |
| 223 | VMSTATE_UNUSED_TEST(is_version_0, 2), |
| 224 | VMSTATE_END_OF_LIST(), |
| 225 | }, |
| 226 | }; |
| 227 | |
| 228 | static SysBusDeviceInfo scoop_sysbus_info = { |
| 229 | .init = scoop_init, |
| 230 | .qdev.name = "scoop", |
| 231 | .qdev.desc = "Scoop2 Sharp custom ASIC", |
| 232 | .qdev.size = sizeof(ScoopInfo), |
| 233 | .qdev.vmsd = &vmstate_scoop_regs, |
| 234 | .qdev.props = (Property[]) { |
| 235 | DEFINE_PROP_END_OF_LIST(), |
| 236 | } |
| 237 | }; |
| 238 | |
| 239 | static void scoop_register(void) |
| 240 | { |
| 241 | sysbus_register_withprop(&scoop_sysbus_info); |
| 242 | } |
| 243 | device_init(scoop_register); |
| 244 | |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 245 | /* Write the bootloader parameters memory area. */ |
| 246 | |
| 247 | #define MAGIC_CHG(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a) |
| 248 | |
blueswir1 | b1d8e52 | 2008-10-26 13:43:07 +0000 | [diff] [blame] | 249 | static struct __attribute__ ((__packed__)) sl_param_info { |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 250 | uint32_t comadj_keyword; |
| 251 | int32_t comadj; |
| 252 | |
| 253 | uint32_t uuid_keyword; |
| 254 | char uuid[16]; |
| 255 | |
| 256 | uint32_t touch_keyword; |
| 257 | int32_t touch_xp; |
| 258 | int32_t touch_yp; |
| 259 | int32_t touch_xd; |
| 260 | int32_t touch_yd; |
| 261 | |
| 262 | uint32_t adadj_keyword; |
| 263 | int32_t adadj; |
| 264 | |
| 265 | uint32_t phad_keyword; |
| 266 | int32_t phadadj; |
| 267 | } zaurus_bootparam = { |
| 268 | .comadj_keyword = MAGIC_CHG('C', 'M', 'A', 'D'), |
| 269 | .comadj = 125, |
| 270 | .uuid_keyword = MAGIC_CHG('U', 'U', 'I', 'D'), |
| 271 | .uuid = { -1 }, |
| 272 | .touch_keyword = MAGIC_CHG('T', 'U', 'C', 'H'), |
| 273 | .touch_xp = -1, |
| 274 | .adadj_keyword = MAGIC_CHG('B', 'V', 'A', 'D'), |
| 275 | .adadj = -1, |
| 276 | .phad_keyword = MAGIC_CHG('P', 'H', 'A', 'D'), |
| 277 | .phadadj = 0x01, |
| 278 | }; |
| 279 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 280 | void sl_bootparam_write(target_phys_addr_t ptr) |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 281 | { |
pbrook | f78630a | 2009-04-09 17:48:30 +0000 | [diff] [blame] | 282 | cpu_physical_memory_write(ptr, (void *)&zaurus_bootparam, |
| 283 | sizeof(struct sl_param_info)); |
balrog | e33d8cd | 2008-06-02 01:20:15 +0000 | [diff] [blame] | 284 | } |