Skip to content

Commit ef24de6

Browse files
committed
wip
1 parent e85973e commit ef24de6

File tree

5 files changed

+214
-61
lines changed

5 files changed

+214
-61
lines changed

hw/arm/amazfit.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "hw/irq.h"
88
#include "hw/loader.h"
99
#include "hw/qdev-properties.h"
10+
#include "hw/qdev-clock.h"
1011
#include "hw/ssi/ssi.h"
1112
#include "qapi/error.h"
1213
#include "ui/console.h"
@@ -40,19 +41,19 @@ void amazfit_key_event(void *opaque, int keycode)
4041
}
4142
}
4243

43-
static void amazfit_mouse_event(void *opaque, int dx, int dy, int dz,
44-
int buttons_state)
45-
{
46-
printf("mouse %d, %d, %d | %d\n", dx, dy, dz, buttons_state);
47-
48-
qemu_set_irq(touchIrq, buttons_state);
49-
qemu_set_irq(touchExtiIrq, buttons_state);
50-
}
44+
/* Main SYSCLK frequency in Hz (120MHz) */
45+
#define SYSCLK_FRQ 120000000ULL
5146

5247
static void bip_init(MachineState *machine)
5348
{
49+
Clock *sysclk;
50+
51+
/* This clock doesn't need migration because it is fixed-frequency */
52+
sysclk = clock_new(OBJECT(machine), "SYSCLK");
53+
clock_set_hz(sysclk, SYSCLK_FRQ);
5454

5555
STM32L467State *dev = STM32L467_SOC(qdev_new(TYPE_STM32L467_SOC));
56+
qdev_connect_clock_in(dev, "sysclk", sysclk);
5657
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
5758

5859
SSIBus *spi_bus = (SSIBus *)qdev_get_child_bus(&dev->spi[2], "ssi"); // SPI3
@@ -68,7 +69,6 @@ static void bip_init(MachineState *machine)
6869

6970
touchIrq = qdev_get_gpio_in(dev->gpio['B' - 'B'], 3);
7071
touchExtiIrq = qdev_get_gpio_in(dev->exti, 3);
71-
qemu_add_mouse_event_handler(amazfit_mouse_event, NULL, 1, "amazfit-mouse");
7272

7373
/* --- QSPI Flash --------------------------------------------- */
7474
SSIBus *qspi = (SSIBus *)qdev_get_child_bus(&dev->qspi, "qspi");
@@ -87,12 +87,13 @@ static void bip_init(MachineState *machine)
8787
"Amazfitbip-FreeRTOS/bin/lcd_test.bin",
8888
0, FLASH_SIZE);
8989
} else {
90-
load_image_targphys("/Users/Marijn/Downloads/bip/image.bin", 0,
90+
load_image_targphys("/Users/hamster/Projects/Bip/FW/out/rom.bin", 0,
9191
FLASH_SIZE);
9292
}
9393

9494
I2CBus *i2c = (I2CBus *)qdev_get_child_bus(&dev->i2c[0], "i2c");
95-
i2c_slave_create_simple(i2c, "it7259", 0x46);
95+
DeviceState *ts = DEVICE(i2c_slave_create_simple(i2c, "it7259", 0x46));
96+
qdev_connect_gpio_out(ts, 0, qemu_irq_split(touchIrq,touchExtiIrq));
9697

9798
armv7m_load_kernel(ARM_CPU(first_cpu), NULL, 0);
9899
}

hw/arm/it7259.c

Lines changed: 163 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,83 +6,204 @@
66
#include "qemu/timer.h"
77
#include "ui/console.h"
88

9+
enum {
10+
state_first,
11+
state_second,
12+
state_ready_for_read,
13+
state_internal_register_mode,
14+
state_internal_register_mode_data,
15+
16+
state_read_buffer,
17+
state_read_point_buffer_ready,
18+
state_end,
19+
};
20+
21+
22+
#define BUFFER_QUERY 0b100
23+
#define BUFFER_POINT 0b111
24+
925
#define TYPE_IT7259 "it7259"
1026
#define IT7259(obj) OBJECT_CHECK(IT7259State, (obj), TYPE_IT7259)
1127

1228
typedef struct {
1329
I2CSlave parent_obj;
1430

15-
int state;
16-
uint8_t buffer;
17-
int reserved;
31+
qemu_irq interrupt;
32+
33+
int state;
34+
int pos;
35+
uint8_t buffer[256];
36+
uint8_t buf;
37+
int reserved;
1838
uint8_t rw;
1939
uint8_t reg;
40+
bool isTouching;
41+
bool isChange;
42+
uint8_t x;
43+
uint8_t y;
44+
uint8_t register_addr;
2045
} IT7259State;
2146

22-
static int it7259_event(I2CSlave *i2c, enum i2c_event event)
23-
{
47+
48+
static void it7259_int_update(IT7259State *s) {
49+
if(s->isChange) {
50+
qemu_irq_pulse(s->interrupt);
51+
}
52+
53+
}
54+
55+
static void it7259_reset(IT7259State *s) {
56+
s->state = state_first;
57+
s->pos = 0;
58+
}
59+
60+
static void it7259_read(IT7259State *s) {
61+
if (s->state == state_internal_register_mode_data) {
62+
s->pos = 0;
63+
} else if (s->state == state_read_buffer) {
64+
s->pos = 0;
65+
if (s->buf == BUFFER_QUERY) {
66+
s->buffer[0] = 0;
67+
s->buffer[0] = s->isTouching << 6;
68+
s->buffer[0] = s->isChange << 7;
69+
} else if (s->buf == BUFFER_POINT) {
70+
memset(s->buffer, 0, sizeof(s->buffer));
71+
s->buffer[0] = 0b0000 << 4 | s->isTouching << 3 | s->isTouching << 0;
72+
s->buffer[1] = 0;
73+
if (s->isTouching) {
74+
s->buffer[2] = s->y;
75+
s->buffer[3] = 0; // high bits of x/y
76+
s->buffer[4] = s->x;
77+
s->buffer[5] = 0x4; // Normal finger contact.
78+
}
79+
s->isChange =false;
80+
it7259_int_update(s);
81+
} else {
82+
assert(false);
83+
}
84+
85+
s->pos = 0;
86+
s->state = state_ready_for_read;
87+
} else { printf("Unknown buffer: %d", s->buf); }
88+
}
89+
90+
static int it7259_event(I2CSlave *i2c, enum i2c_event event) {
2491
IT7259State *s = IT7259(i2c);
2592

93+
printf("[IT7259] event: %d\n", event);
2694
switch (event) {
27-
case I2C_START_SEND:
28-
printf("[IT7259] START SEND\n", event);
95+
case I2C_START_RECV:
96+
it7259_read(s);
2997
break;
98+
case I2C_START_SEND:
99+
it7259_reset(s);
30100
default:
31101
case I2C_FINISH:
32-
case I2C_START_RECV:
33-
printf("[IT7259] event %d\n", event);
34102
break;
35103
}
36104

37105
return 0;
38106
}
39107

40-
static uint8_t it7259_rx(I2CSlave *i2c)
41-
{
108+
static uint8_t it7259_rx(I2CSlave *i2c) {
42109
IT7259State *s = IT7259(i2c);
43110

44-
assert(s->state == 2);
45-
s->state = 0;
46-
switch (s->reg) {
47-
case 0x32:
48-
return 0x59; // Device ID 2
49-
case 0x33:
50-
return 0x72; // Device ID 1
111+
if (s->state == state_internal_register_mode_data) {
112+
// Only allow single reads
113+
assert(s->pos == 0);
114+
s->pos++;
115+
switch (s->register_addr) {
116+
case 0x32:
117+
return 0x59;
118+
case 0x33:
119+
return 0x72;
120+
default:
121+
printf("[IT7259] Read internal register: 0x%02X\n", s->register_addr);
122+
break;
123+
}
124+
125+
} else {
126+
127+
assert(s->state == state_ready_for_read);
128+
printf("[IT7259] read 0x%02X\n", s->buffer[s->pos]);
129+
return s->buffer[s->pos++];
51130
}
52131

53-
return 0;
132+
return 0xFF;
54133
}
55134

56-
static int it7259_tx(I2CSlave *i2c, uint8_t data)
57-
{
135+
static int it7259_tx(I2CSlave *i2c, uint8_t data) {
58136
IT7259State *s = IT7259(i2c);
59137

60-
if (s->state == 0) {
61-
s->reserved = data & 0b1111;
62-
s->buffer = (data >> 4)& 0b111;
63-
s->rw = data>>7;
64-
assert(s->reserved == 0b0000);
65-
assert(s->buffer == 0b111);
66-
assert(s->rw == 0b0);
67-
s->state++;
68-
} else if(s->state == 1) {
69-
s->reg = data;
70-
s->state++;
138+
printf("[IT7259] write 0x%02X\n", data);
139+
140+
if (s->state == state_first) {
141+
uint8_t m = (data >> 4 & 0b1);
142+
uint8_t addr = (data >> 5 & 0b11);
143+
uint8_t rw = (data >> 7 & 0b1);
144+
if (addr == 0b11 && m == 0b1) {
145+
assert(rw == 0b0); // Datasheet only uses 0x70 for the first byte
146+
s->state = state_internal_register_mode;
147+
} else {
148+
s->reserved = data & 0b11111;
149+
s->buf = (data >> 5) & 0b111;
150+
// assert(s->reserved == 0b00000);
151+
if (s->buf == BUFFER_POINT || s->buf == BUFFER_QUERY) {
152+
s->state = state_read_buffer;
153+
} else {
154+
printf("[IT7259] Unknown buffer: %d\n", s->buf);
155+
assert(false);
156+
}
157+
}
158+
} else if (s->state == state_internal_register_mode) {
159+
s->register_addr = data;
160+
s->state = state_internal_register_mode_data;
161+
} else {
162+
s->buffer[s->pos++] = data;
71163
}
72164

73-
printf("[IT7259] cmd: 0x%02X\n", data);
165+
return 0;
166+
}
74167

168+
static void it7259_ts_event(void *opaque,
169+
int x, int y, int z, int buttons_state) {
170+
IT7259State *s = opaque;
171+
172+
173+
if (buttons_state & MOUSE_EVENT_LBUTTON) {
174+
if (!s->isTouching) {
175+
s->isTouching = true;
176+
s->isChange = true;
177+
}
178+
if (s->x != x) {
179+
s->isChange = true;
180+
s->x = (uint8_t) ((float) x / (float) 0x7FFF * 176.0);
181+
}
182+
if (s->y != y) {
183+
s->isChange = true;
184+
s->y = (uint8_t) ((float) y / (float) 0x7FFF * 176.0);
185+
}
186+
printf("[it7259] Mouse: %d, %d\n", s->x, s->y);
187+
} else {
188+
if (s->isTouching) {
189+
s->isTouching = false;
190+
s->isChange = true;
191+
}
192+
}
75193

76-
return 0;
194+
it7259_int_update(s);
77195
}
78196

79-
static void it7259_realize(DeviceState *dev, Error **errp)
80-
{
197+
static void it7259_realize(DeviceState *dev, Error **errp) {
81198
IT7259State *s = IT7259(dev);
199+
200+
qdev_init_gpio_out(dev, &s->interrupt, 1);
201+
202+
qemu_add_mouse_event_handler(it7259_ts_event, s, 1, "amazfit-mouse");
203+
it7259_reset(s);
82204
}
83205

84-
static void it7259_class_init(ObjectClass *klass, void *data)
85-
{
206+
static void it7259_class_init(ObjectClass *klass, void *data) {
86207
DeviceClass *dc = DEVICE_CLASS(klass);
87208
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
88209

@@ -93,10 +214,10 @@ static void it7259_class_init(ObjectClass *klass, void *data)
93214
}
94215

95216
static const TypeInfo it7259_info = {
96-
.name = TYPE_IT7259,
97-
.parent = TYPE_I2C_SLAVE,
98-
.instance_size = sizeof(IT7259State),
99-
.class_init = it7259_class_init,
217+
.name = TYPE_IT7259,
218+
.parent = TYPE_I2C_SLAVE,
219+
.instance_size = sizeof(IT7259State),
220+
.class_init = it7259_class_init,
100221
};
101222

102223
static void it7259_register_types(void) { type_register_static(&it7259_info); }

hw/arm/stm32l467_soc.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "hw/loader.h"
1111
#include "hw/misc/unimp.h"
1212
#include "hw/sysbus.h"
13+
#include "hw/qdev-clock.h"
1314
#include "qapi/error.h"
1415
#include "qemu/log.h"
1516
#include "qom/object.h"
@@ -225,6 +226,9 @@ static void stm32l467_soc_initfn(Object *obj)
225226
object_initialize_child(obj, "SPI3", &s->spi[2], TYPE_STM32L476_SPI);
226227
s->spi[2].rxdrq = s->dma.channels[0].drq[0b0011]; /* RX */
227228
s->spi[2].txdrq = s->dma.channels[1].drq[0b0011]; /* TX */
229+
230+
s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
231+
s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
228232
}
229233

230234
static void stm32l467_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -234,6 +238,30 @@ static void stm32l467_soc_realize(DeviceState *dev_soc, Error **errp)
234238

235239
MemoryRegion *system_memory = get_system_memory();
236240

241+
/*
242+
* We use s->refclk internally and only define it with qdev_init_clock_in()
243+
* so it is correctly parented and not leaked on an init/deinit; it is not
244+
* intended as an externally exposed clock.
245+
*/
246+
if (clock_has_source(s->refclk)) {
247+
error_setg(errp, "refclk clock must not be wired up by the board code");
248+
return;
249+
}
250+
251+
if (!clock_has_source(s->sysclk)) {
252+
error_setg(errp, "sysclk clock must be wired up by the board code");
253+
return;
254+
}
255+
256+
/*
257+
* TODO: ideally we should model the SoC RCC and its ability to
258+
* change the sysclk frequency and define different sysclk sources.
259+
*/
260+
261+
/* The refclk always runs at frequency HCLK / 8 */
262+
clock_set_mul_div(s->refclk, 8, 1);
263+
clock_set_source(s->refclk, s->sysclk);
264+
237265
create_unimplemented_layer("IO", 0, 0xFFFFFFFF);
238266

239267
create_unimplemented_layer("TIM2", TIM2_BASE, 0x400);
@@ -310,6 +338,8 @@ static void stm32l467_soc_realize(DeviceState *dev_soc, Error **errp)
310338
DeviceState *armv7m = DEVICE(&s->armv7m);
311339
qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
312340
qdev_prop_set_uint32(armv7m, "num-irq", 82);
341+
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
342+
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
313343
object_property_set_link(OBJECT(&s->armv7m), "memory",
314344
OBJECT(system_memory), &error_abort);
315345
if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
@@ -397,8 +427,6 @@ static void stm32l467_soc_realize(DeviceState *dev_soc, Error **errp)
397427
sysbus_connect_irq(busdev, 4, qdev_get_gpio_in(armv7m, EXTI4_IRQn));
398428
sysbus_connect_irq(busdev, 5, qdev_get_gpio_in(armv7m, EXTI9_5_IRQn));
399429
sysbus_connect_irq(busdev, 6, qdev_get_gpio_in(armv7m, EXTI15_10_IRQn));
400-
401-
system_clock_scale = 1000;
402430
}
403431

404432
static Property stm32l467_soc_properties[] = {

0 commit comments

Comments
 (0)