Commit 5c1c390feac308327eee376845d90355b16615b9
1 parent
4a2c8ac2
Implement OMAP on-chip RTC (Linux guest date/time now matches with host).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3515 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
433 additions
and
0 deletions
hw/omap.c
| @@ -4018,6 +4018,432 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s) | @@ -4018,6 +4018,432 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s) | ||
| 4018 | return s->bus; | 4018 | return s->bus; |
| 4019 | } | 4019 | } |
| 4020 | 4020 | ||
| 4021 | +/* Real-time Clock module */ | ||
| 4022 | +struct omap_rtc_s { | ||
| 4023 | + target_phys_addr_t base; | ||
| 4024 | + qemu_irq irq; | ||
| 4025 | + qemu_irq alarm; | ||
| 4026 | + QEMUTimer *clk; | ||
| 4027 | + | ||
| 4028 | + uint8_t interrupts; | ||
| 4029 | + uint8_t status; | ||
| 4030 | + int16_t comp_reg; | ||
| 4031 | + int running; | ||
| 4032 | + int pm_am; | ||
| 4033 | + int auto_comp; | ||
| 4034 | + int round; | ||
| 4035 | + struct tm *(*convert)(const time_t *timep, struct tm *result); | ||
| 4036 | + struct tm alarm_tm; | ||
| 4037 | + time_t alarm_ti; | ||
| 4038 | + | ||
| 4039 | + struct tm current_tm; | ||
| 4040 | + time_t ti; | ||
| 4041 | + uint64_t tick; | ||
| 4042 | +}; | ||
| 4043 | + | ||
| 4044 | +static void omap_rtc_interrupts_update(struct omap_rtc_s *s) | ||
| 4045 | +{ | ||
| 4046 | + qemu_set_irq(s->alarm, (s->status >> 6) & 1); | ||
| 4047 | +} | ||
| 4048 | + | ||
| 4049 | +static void omap_rtc_alarm_update(struct omap_rtc_s *s) | ||
| 4050 | +{ | ||
| 4051 | + s->alarm_ti = mktime(&s->alarm_tm); | ||
| 4052 | + if (s->alarm_ti == -1) | ||
| 4053 | + printf("%s: conversion failed\n", __FUNCTION__); | ||
| 4054 | +} | ||
| 4055 | + | ||
| 4056 | +static inline uint8_t omap_rtc_bcd(int num) | ||
| 4057 | +{ | ||
| 4058 | + return ((num / 10) << 4) | (num % 10); | ||
| 4059 | +} | ||
| 4060 | + | ||
| 4061 | +static inline int omap_rtc_bin(uint8_t num) | ||
| 4062 | +{ | ||
| 4063 | + return (num & 15) + 10 * (num >> 4); | ||
| 4064 | +} | ||
| 4065 | + | ||
| 4066 | +static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) | ||
| 4067 | +{ | ||
| 4068 | + struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; | ||
| 4069 | + int offset = addr - s->base; | ||
| 4070 | + uint8_t i; | ||
| 4071 | + | ||
| 4072 | + switch (offset) { | ||
| 4073 | + case 0x00: /* SECONDS_REG */ | ||
| 4074 | + return omap_rtc_bcd(s->current_tm.tm_sec); | ||
| 4075 | + | ||
| 4076 | + case 0x04: /* MINUTES_REG */ | ||
| 4077 | + return omap_rtc_bcd(s->current_tm.tm_min); | ||
| 4078 | + | ||
| 4079 | + case 0x08: /* HOURS_REG */ | ||
| 4080 | + if (s->pm_am) | ||
| 4081 | + return ((s->current_tm.tm_hour > 11) << 7) | | ||
| 4082 | + omap_rtc_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); | ||
| 4083 | + else | ||
| 4084 | + return omap_rtc_bcd(s->current_tm.tm_hour); | ||
| 4085 | + | ||
| 4086 | + case 0x0c: /* DAYS_REG */ | ||
| 4087 | + return omap_rtc_bcd(s->current_tm.tm_mday); | ||
| 4088 | + | ||
| 4089 | + case 0x10: /* MONTHS_REG */ | ||
| 4090 | + return omap_rtc_bcd(s->current_tm.tm_mon + 1); | ||
| 4091 | + | ||
| 4092 | + case 0x14: /* YEARS_REG */ | ||
| 4093 | + return omap_rtc_bcd(s->current_tm.tm_year % 100); | ||
| 4094 | + | ||
| 4095 | + case 0x18: /* WEEK_REG */ | ||
| 4096 | + return s->current_tm.tm_wday; | ||
| 4097 | + | ||
| 4098 | + case 0x20: /* ALARM_SECONDS_REG */ | ||
| 4099 | + return omap_rtc_bcd(s->alarm_tm.tm_sec); | ||
| 4100 | + | ||
| 4101 | + case 0x24: /* ALARM_MINUTES_REG */ | ||
| 4102 | + return omap_rtc_bcd(s->alarm_tm.tm_min); | ||
| 4103 | + | ||
| 4104 | + case 0x28: /* ALARM_HOURS_REG */ | ||
| 4105 | + if (s->pm_am) | ||
| 4106 | + return ((s->alarm_tm.tm_hour > 11) << 7) | | ||
| 4107 | + omap_rtc_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); | ||
| 4108 | + else | ||
| 4109 | + return omap_rtc_bcd(s->alarm_tm.tm_hour); | ||
| 4110 | + | ||
| 4111 | + case 0x2c: /* ALARM_DAYS_REG */ | ||
| 4112 | + return omap_rtc_bcd(s->alarm_tm.tm_mday); | ||
| 4113 | + | ||
| 4114 | + case 0x30: /* ALARM_MONTHS_REG */ | ||
| 4115 | + return omap_rtc_bcd(s->alarm_tm.tm_mon + 1); | ||
| 4116 | + | ||
| 4117 | + case 0x34: /* ALARM_YEARS_REG */ | ||
| 4118 | + return omap_rtc_bcd(s->alarm_tm.tm_year % 100); | ||
| 4119 | + | ||
| 4120 | + case 0x40: /* RTC_CTRL_REG */ | ||
| 4121 | + return (s->pm_am << 3) | (s->auto_comp << 2) | | ||
| 4122 | + (s->round << 1) | s->running; | ||
| 4123 | + | ||
| 4124 | + case 0x44: /* RTC_STATUS_REG */ | ||
| 4125 | + i = s->status; | ||
| 4126 | + s->status &= ~0x3d; | ||
| 4127 | + return i; | ||
| 4128 | + | ||
| 4129 | + case 0x48: /* RTC_INTERRUPTS_REG */ | ||
| 4130 | + return s->interrupts; | ||
| 4131 | + | ||
| 4132 | + case 0x4c: /* RTC_COMP_LSB_REG */ | ||
| 4133 | + return ((uint16_t) s->comp_reg) & 0xff; | ||
| 4134 | + | ||
| 4135 | + case 0x50: /* RTC_COMP_MSB_REG */ | ||
| 4136 | + return ((uint16_t) s->comp_reg) >> 8; | ||
| 4137 | + } | ||
| 4138 | + | ||
| 4139 | + OMAP_BAD_REG(addr); | ||
| 4140 | + return 0; | ||
| 4141 | +} | ||
| 4142 | + | ||
| 4143 | +static void omap_rtc_write(void *opaque, target_phys_addr_t addr, | ||
| 4144 | + uint32_t value) | ||
| 4145 | +{ | ||
| 4146 | + struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; | ||
| 4147 | + int offset = addr - s->base; | ||
| 4148 | + struct tm new_tm; | ||
| 4149 | + time_t ti[2]; | ||
| 4150 | + | ||
| 4151 | + switch (offset) { | ||
| 4152 | + case 0x00: /* SECONDS_REG */ | ||
| 4153 | +#if ALMDEBUG | ||
| 4154 | + printf("RTC SEC_REG <-- %02x\n", value); | ||
| 4155 | +#endif | ||
| 4156 | + s->ti -= s->current_tm.tm_sec; | ||
| 4157 | + s->ti += omap_rtc_bin(value); | ||
| 4158 | + return; | ||
| 4159 | + | ||
| 4160 | + case 0x04: /* MINUTES_REG */ | ||
| 4161 | +#if ALMDEBUG | ||
| 4162 | + printf("RTC MIN_REG <-- %02x\n", value); | ||
| 4163 | +#endif | ||
| 4164 | + s->ti -= s->current_tm.tm_min * 60; | ||
| 4165 | + s->ti += omap_rtc_bin(value) * 60; | ||
| 4166 | + return; | ||
| 4167 | + | ||
| 4168 | + case 0x08: /* HOURS_REG */ | ||
| 4169 | +#if ALMDEBUG | ||
| 4170 | + printf("RTC HRS_REG <-- %02x\n", value); | ||
| 4171 | +#endif | ||
| 4172 | + s->ti -= s->current_tm.tm_hour * 3600; | ||
| 4173 | + if (s->pm_am) { | ||
| 4174 | + s->ti += (omap_rtc_bin(value & 0x3f) & 12) * 3600; | ||
| 4175 | + s->ti += ((value >> 7) & 1) * 43200; | ||
| 4176 | + } else | ||
| 4177 | + s->ti += omap_rtc_bin(value & 0x3f) * 3600; | ||
| 4178 | + return; | ||
| 4179 | + | ||
| 4180 | + case 0x0c: /* DAYS_REG */ | ||
| 4181 | +#if ALMDEBUG | ||
| 4182 | + printf("RTC DAY_REG <-- %02x\n", value); | ||
| 4183 | +#endif | ||
| 4184 | + s->ti -= s->current_tm.tm_mday * 86400; | ||
| 4185 | + s->ti += omap_rtc_bin(value) * 86400; | ||
| 4186 | + return; | ||
| 4187 | + | ||
| 4188 | + case 0x10: /* MONTHS_REG */ | ||
| 4189 | +#if ALMDEBUG | ||
| 4190 | + printf("RTC MTH_REG <-- %02x\n", value); | ||
| 4191 | +#endif | ||
| 4192 | + memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); | ||
| 4193 | + new_tm.tm_mon = omap_rtc_bin(value); | ||
| 4194 | + ti[0] = mktime(&s->current_tm); | ||
| 4195 | + ti[1] = mktime(&new_tm); | ||
| 4196 | + | ||
| 4197 | + if (ti[0] != -1 && ti[1] != -1) { | ||
| 4198 | + s->ti -= ti[0]; | ||
| 4199 | + s->ti += ti[1]; | ||
| 4200 | + } else { | ||
| 4201 | + /* A less accurate version */ | ||
| 4202 | + s->ti -= s->current_tm.tm_mon * 2592000; | ||
| 4203 | + s->ti += omap_rtc_bin(value) * 2592000; | ||
| 4204 | + } | ||
| 4205 | + return; | ||
| 4206 | + | ||
| 4207 | + case 0x14: /* YEARS_REG */ | ||
| 4208 | +#if ALMDEBUG | ||
| 4209 | + printf("RTC YRS_REG <-- %02x\n", value); | ||
| 4210 | +#endif | ||
| 4211 | + memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); | ||
| 4212 | + new_tm.tm_year += omap_rtc_bin(value) - (new_tm.tm_year % 100); | ||
| 4213 | + ti[0] = mktime(&s->current_tm); | ||
| 4214 | + ti[1] = mktime(&new_tm); | ||
| 4215 | + | ||
| 4216 | + if (ti[0] != -1 && ti[1] != -1) { | ||
| 4217 | + s->ti -= ti[0]; | ||
| 4218 | + s->ti += ti[1]; | ||
| 4219 | + } else { | ||
| 4220 | + /* A less accurate version */ | ||
| 4221 | + s->ti -= (s->current_tm.tm_year % 100) * 31536000; | ||
| 4222 | + s->ti += omap_rtc_bin(value) * 31536000; | ||
| 4223 | + } | ||
| 4224 | + return; | ||
| 4225 | + | ||
| 4226 | + case 0x18: /* WEEK_REG */ | ||
| 4227 | + return; /* Ignored */ | ||
| 4228 | + | ||
| 4229 | + case 0x20: /* ALARM_SECONDS_REG */ | ||
| 4230 | +#if ALMDEBUG | ||
| 4231 | + printf("ALM SEC_REG <-- %02x\n", value); | ||
| 4232 | +#endif | ||
| 4233 | + s->alarm_tm.tm_sec = omap_rtc_bin(value); | ||
| 4234 | + omap_rtc_alarm_update(s); | ||
| 4235 | + return; | ||
| 4236 | + | ||
| 4237 | + case 0x24: /* ALARM_MINUTES_REG */ | ||
| 4238 | +#if ALMDEBUG | ||
| 4239 | + printf("ALM MIN_REG <-- %02x\n", value); | ||
| 4240 | +#endif | ||
| 4241 | + s->alarm_tm.tm_min = omap_rtc_bin(value); | ||
| 4242 | + omap_rtc_alarm_update(s); | ||
| 4243 | + return; | ||
| 4244 | + | ||
| 4245 | + case 0x28: /* ALARM_HOURS_REG */ | ||
| 4246 | +#if ALMDEBUG | ||
| 4247 | + printf("ALM HRS_REG <-- %02x\n", value); | ||
| 4248 | +#endif | ||
| 4249 | + if (s->pm_am) | ||
| 4250 | + s->alarm_tm.tm_hour = | ||
| 4251 | + ((omap_rtc_bin(value & 0x3f)) % 12) + | ||
| 4252 | + ((value >> 7) & 1) * 12; | ||
| 4253 | + else | ||
| 4254 | + s->alarm_tm.tm_hour = omap_rtc_bin(value); | ||
| 4255 | + omap_rtc_alarm_update(s); | ||
| 4256 | + return; | ||
| 4257 | + | ||
| 4258 | + case 0x2c: /* ALARM_DAYS_REG */ | ||
| 4259 | +#if ALMDEBUG | ||
| 4260 | + printf("ALM DAY_REG <-- %02x\n", value); | ||
| 4261 | +#endif | ||
| 4262 | + s->alarm_tm.tm_mday = omap_rtc_bin(value); | ||
| 4263 | + omap_rtc_alarm_update(s); | ||
| 4264 | + return; | ||
| 4265 | + | ||
| 4266 | + case 0x30: /* ALARM_MONTHS_REG */ | ||
| 4267 | +#if ALMDEBUG | ||
| 4268 | + printf("ALM MON_REG <-- %02x\n", value); | ||
| 4269 | +#endif | ||
| 4270 | + s->alarm_tm.tm_mon = omap_rtc_bin(value); | ||
| 4271 | + omap_rtc_alarm_update(s); | ||
| 4272 | + return; | ||
| 4273 | + | ||
| 4274 | + case 0x34: /* ALARM_YEARS_REG */ | ||
| 4275 | +#if ALMDEBUG | ||
| 4276 | + printf("ALM YRS_REG <-- %02x\n", value); | ||
| 4277 | +#endif | ||
| 4278 | + s->alarm_tm.tm_year = omap_rtc_bin(value); | ||
| 4279 | + omap_rtc_alarm_update(s); | ||
| 4280 | + return; | ||
| 4281 | + | ||
| 4282 | + case 0x40: /* RTC_CTRL_REG */ | ||
| 4283 | +#if ALMDEBUG | ||
| 4284 | + printf("RTC CONTROL <-- %02x\n", value); | ||
| 4285 | +#endif | ||
| 4286 | + s->pm_am = (value >> 3) & 1; | ||
| 4287 | + s->auto_comp = (value >> 2) & 1; | ||
| 4288 | + s->round = (value >> 1) & 1; | ||
| 4289 | + s->running = value & 1; | ||
| 4290 | + s->status &= 0xfd; | ||
| 4291 | + s->status |= s->running << 1; | ||
| 4292 | + return; | ||
| 4293 | + | ||
| 4294 | + case 0x44: /* RTC_STATUS_REG */ | ||
| 4295 | +#if ALMDEBUG | ||
| 4296 | + printf("RTC STATUSL <-- %02x\n", value); | ||
| 4297 | +#endif | ||
| 4298 | + s->status &= ~((value & 0xc0) ^ 0x80); | ||
| 4299 | + omap_rtc_interrupts_update(s); | ||
| 4300 | + return; | ||
| 4301 | + | ||
| 4302 | + case 0x48: /* RTC_INTERRUPTS_REG */ | ||
| 4303 | +#if ALMDEBUG | ||
| 4304 | + printf("RTC INTRS <-- %02x\n", value); | ||
| 4305 | +#endif | ||
| 4306 | + s->interrupts = value; | ||
| 4307 | + return; | ||
| 4308 | + | ||
| 4309 | + case 0x4c: /* RTC_COMP_LSB_REG */ | ||
| 4310 | +#if ALMDEBUG | ||
| 4311 | + printf("RTC COMPLSB <-- %02x\n", value); | ||
| 4312 | +#endif | ||
| 4313 | + s->comp_reg &= 0xff00; | ||
| 4314 | + s->comp_reg |= 0x00ff & value; | ||
| 4315 | + return; | ||
| 4316 | + | ||
| 4317 | + case 0x50: /* RTC_COMP_MSB_REG */ | ||
| 4318 | +#if ALMDEBUG | ||
| 4319 | + printf("RTC COMPMSB <-- %02x\n", value); | ||
| 4320 | +#endif | ||
| 4321 | + s->comp_reg &= 0x00ff; | ||
| 4322 | + s->comp_reg |= 0xff00 & (value << 8); | ||
| 4323 | + return; | ||
| 4324 | + | ||
| 4325 | + default: | ||
| 4326 | + OMAP_BAD_REG(addr); | ||
| 4327 | + return; | ||
| 4328 | + } | ||
| 4329 | +} | ||
| 4330 | + | ||
| 4331 | +static CPUReadMemoryFunc *omap_rtc_readfn[] = { | ||
| 4332 | + omap_rtc_read, | ||
| 4333 | + omap_badwidth_read8, | ||
| 4334 | + omap_badwidth_read8, | ||
| 4335 | +}; | ||
| 4336 | + | ||
| 4337 | +static CPUWriteMemoryFunc *omap_rtc_writefn[] = { | ||
| 4338 | + omap_rtc_write, | ||
| 4339 | + omap_badwidth_write8, | ||
| 4340 | + omap_badwidth_write8, | ||
| 4341 | +}; | ||
| 4342 | + | ||
| 4343 | +static void omap_rtc_tick(void *opaque) | ||
| 4344 | +{ | ||
| 4345 | + struct omap_rtc_s *s = opaque; | ||
| 4346 | + | ||
| 4347 | + if (s->round) { | ||
| 4348 | + /* Round to nearest full minute. */ | ||
| 4349 | + if (s->current_tm.tm_sec < 30) | ||
| 4350 | + s->ti -= s->current_tm.tm_sec; | ||
| 4351 | + else | ||
| 4352 | + s->ti += 60 - s->current_tm.tm_sec; | ||
| 4353 | + | ||
| 4354 | + s->round = 0; | ||
| 4355 | + } | ||
| 4356 | + | ||
| 4357 | + localtime_r(&s->ti, &s->current_tm); | ||
| 4358 | + | ||
| 4359 | + if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { | ||
| 4360 | + s->status |= 0x40; | ||
| 4361 | + omap_rtc_interrupts_update(s); | ||
| 4362 | + } | ||
| 4363 | + | ||
| 4364 | + if (s->interrupts & 0x04) | ||
| 4365 | + switch (s->interrupts & 3) { | ||
| 4366 | + case 0: | ||
| 4367 | + s->status |= 0x04; | ||
| 4368 | + qemu_irq_raise(s->irq); | ||
| 4369 | + break; | ||
| 4370 | + case 1: | ||
| 4371 | + if (s->current_tm.tm_sec) | ||
| 4372 | + break; | ||
| 4373 | + s->status |= 0x08; | ||
| 4374 | + qemu_irq_raise(s->irq); | ||
| 4375 | + break; | ||
| 4376 | + case 2: | ||
| 4377 | + if (s->current_tm.tm_sec || s->current_tm.tm_min) | ||
| 4378 | + break; | ||
| 4379 | + s->status |= 0x10; | ||
| 4380 | + qemu_irq_raise(s->irq); | ||
| 4381 | + break; | ||
| 4382 | + case 3: | ||
| 4383 | + if (s->current_tm.tm_sec || | ||
| 4384 | + s->current_tm.tm_min || s->current_tm.tm_hour) | ||
| 4385 | + break; | ||
| 4386 | + s->status |= 0x20; | ||
| 4387 | + qemu_irq_raise(s->irq); | ||
| 4388 | + break; | ||
| 4389 | + } | ||
| 4390 | + | ||
| 4391 | + /* Move on */ | ||
| 4392 | + if (s->running) | ||
| 4393 | + s->ti ++; | ||
| 4394 | + s->tick += 1000; | ||
| 4395 | + | ||
| 4396 | + /* | ||
| 4397 | + * Every full hour add a rough approximation of the compensation | ||
| 4398 | + * register to the 32kHz Timer (which drives the RTC) value. | ||
| 4399 | + */ | ||
| 4400 | + if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min) | ||
| 4401 | + s->tick += s->comp_reg * 1000 / 32768; | ||
| 4402 | + | ||
| 4403 | + qemu_mod_timer(s->clk, s->tick); | ||
| 4404 | +} | ||
| 4405 | + | ||
| 4406 | +void omap_rtc_reset(struct omap_rtc_s *s) | ||
| 4407 | +{ | ||
| 4408 | + s->interrupts = 0; | ||
| 4409 | + s->comp_reg = 0; | ||
| 4410 | + s->running = 0; | ||
| 4411 | + s->pm_am = 0; | ||
| 4412 | + s->auto_comp = 0; | ||
| 4413 | + s->round = 0; | ||
| 4414 | + s->tick = qemu_get_clock(rt_clock); | ||
| 4415 | + memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); | ||
| 4416 | + s->alarm_tm.tm_mday = 0x01; | ||
| 4417 | + s->status = 1 << 7; | ||
| 4418 | + time(&s->ti); | ||
| 4419 | + s->ti = mktime(s->convert(&s->ti, &s->current_tm)); | ||
| 4420 | + | ||
| 4421 | + omap_rtc_alarm_update(s); | ||
| 4422 | + omap_rtc_tick(s); | ||
| 4423 | +} | ||
| 4424 | + | ||
| 4425 | +struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, | ||
| 4426 | + qemu_irq *irq, omap_clk clk) | ||
| 4427 | +{ | ||
| 4428 | + int iomemtype; | ||
| 4429 | + struct omap_rtc_s *s = (struct omap_rtc_s *) | ||
| 4430 | + qemu_mallocz(sizeof(struct omap_rtc_s)); | ||
| 4431 | + | ||
| 4432 | + s->base = base; | ||
| 4433 | + s->irq = irq[0]; | ||
| 4434 | + s->alarm = irq[1]; | ||
| 4435 | + s->clk = qemu_new_timer(rt_clock, omap_rtc_tick, s); | ||
| 4436 | + s->convert = rtc_utc ? gmtime_r : localtime_r; | ||
| 4437 | + | ||
| 4438 | + omap_rtc_reset(s); | ||
| 4439 | + | ||
| 4440 | + iomemtype = cpu_register_io_memory(0, omap_rtc_readfn, | ||
| 4441 | + omap_rtc_writefn, s); | ||
| 4442 | + cpu_register_physical_memory(s->base, 0x800, iomemtype); | ||
| 4443 | + | ||
| 4444 | + return s; | ||
| 4445 | +} | ||
| 4446 | + | ||
| 4021 | /* General chip reset */ | 4447 | /* General chip reset */ |
| 4022 | static void omap_mpu_reset(void *opaque) | 4448 | static void omap_mpu_reset(void *opaque) |
| 4023 | { | 4449 | { |
| @@ -4051,6 +4477,7 @@ static void omap_mpu_reset(void *opaque) | @@ -4051,6 +4477,7 @@ static void omap_mpu_reset(void *opaque) | ||
| 4051 | omap_pwl_reset(mpu); | 4477 | omap_pwl_reset(mpu); |
| 4052 | omap_pwt_reset(mpu); | 4478 | omap_pwt_reset(mpu); |
| 4053 | omap_i2c_reset(mpu->i2c); | 4479 | omap_i2c_reset(mpu->i2c); |
| 4480 | + omap_rtc_reset(mpu->rtc); | ||
| 4054 | cpu_reset(mpu->env); | 4481 | cpu_reset(mpu->env); |
| 4055 | } | 4482 | } |
| 4056 | 4483 | ||
| @@ -4178,6 +4605,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | @@ -4178,6 +4605,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | ||
| 4178 | s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], | 4605 | s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], |
| 4179 | &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); | 4606 | &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); |
| 4180 | 4607 | ||
| 4608 | + s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], | ||
| 4609 | + omap_findclk(s, "clk32-kHz")); | ||
| 4181 | qemu_register_reset(omap_mpu_reset, s); | 4610 | qemu_register_reset(omap_mpu_reset, s); |
| 4182 | 4611 | ||
| 4183 | return s; | 4612 | return s; |
hw/omap.h
| @@ -480,6 +480,10 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, | @@ -480,6 +480,10 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, | ||
| 480 | qemu_irq irq, qemu_irq *dma, omap_clk clk); | 480 | qemu_irq irq, qemu_irq *dma, omap_clk clk); |
| 481 | i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); | 481 | i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); |
| 482 | 482 | ||
| 483 | +struct omap_rtc_s; | ||
| 484 | +struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, | ||
| 485 | + qemu_irq *irq, omap_clk clk); | ||
| 486 | + | ||
| 483 | /* omap_lcdc.c */ | 487 | /* omap_lcdc.c */ |
| 484 | struct omap_lcd_panel_s; | 488 | struct omap_lcd_panel_s; |
| 485 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); | 489 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); |