summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/debug_menu.c6
-rw-r--r--firmware/drivers/adc-as3514.c21
-rw-r--r--firmware/export/ascodec.h2
-rw-r--r--firmware/export/system.h15
-rw-r--r--firmware/panic.c8
-rw-r--r--firmware/system.c29
-rw-r--r--firmware/target/arm/as3525/ascodec-as3525.c571
-rw-r--r--firmware/target/arm/as3525/debug-as3525.c30
-rw-r--r--firmware/target/arm/as3525/system-as3525.c37
-rw-r--r--firmware/target/arm/as3525/system-target.h21
-rw-r--r--firmware/target/arm/pp/system-pp5002.c19
-rw-r--r--firmware/target/arm/pp/system-pp502x.c21
-rw-r--r--firmware/target/arm/pp/system-target.h17
13 files changed, 641 insertions, 156 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index d35f40229e..000dbdc4fc 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -796,6 +796,12 @@ static bool dbg_cpufreq(void)
796 lcd_putsf(0, line++, "Frequency: %ld.%ld MHz", temp, (FREQ-temp*1000000)/100000); 796 lcd_putsf(0, line++, "Frequency: %ld.%ld MHz", temp, (FREQ-temp*1000000)/100000);
797 lcd_putsf(0, line++, "boost_counter: %d", get_cpu_boost_counter()); 797 lcd_putsf(0, line++, "boost_counter: %d", get_cpu_boost_counter());
798 798
799#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
800 extern int get_cpu_voltage_setting(void);
801 temp = get_cpu_voltage_setting();
802 lcd_putsf(0, line++, "CPU voltage: %d.%03dV", temp / 1000, temp % 1000);
803#endif
804
799 lcd_update(); 805 lcd_update();
800 button = get_action(CONTEXT_STD,HZ/10); 806 button = get_action(CONTEXT_STD,HZ/10);
801 807
diff --git a/firmware/drivers/adc-as3514.c b/firmware/drivers/adc-as3514.c
index 3b411a379d..9a81a52cc7 100644
--- a/firmware/drivers/adc-as3514.c
+++ b/firmware/drivers/adc-as3514.c
@@ -26,18 +26,35 @@
26/* Read 10-bit channel data */ 26/* Read 10-bit channel data */
27unsigned short adc_read(int channel) 27unsigned short adc_read(int channel)
28{ 28{
29 unsigned char buf[2]; 29 unsigned short data = 0;
30
31 if ((unsigned)channel >= NUM_ADC_CHANNELS)
32 return 0;
30 33
31 ascodec_lock(); 34 ascodec_lock();
32 35
33 /* Select channel */ 36 /* Select channel */
34 ascodec_write(AS3514_ADC_0, (channel << 4)); 37 ascodec_write(AS3514_ADC_0, (channel << 4));
38 /*
39 * The AS3514 ADC will trigger an interrupt when the conversion
40 * is finished, if the corresponding enable bit in IRQ_ENRD2
41 * is set.
42 * Previously the code did not wait and this apparently did
43 * not pose any problems, but this should be more correct.
44 * Without the wait the data read back may be completely or
45 * partially (first one of the two bytes) stale.
46 */
47 ascodec_wait_adc_finished();
48
35 49
50 /* Read data */
51 unsigned char buf[2] = { 0, 0 };
36 ascodec_readbytes(AS3514_ADC_0, 2, buf); 52 ascodec_readbytes(AS3514_ADC_0, 2, buf);
53 data = (((buf[0] & 0x3) << 8) | buf[1]);
37 54
38 ascodec_unlock(); 55 ascodec_unlock();
39 56
40 return (((buf[0] & 0x3) << 8) | buf[1]); 57 return data;
41} 58}
42 59
43void adc_init(void) 60void adc_init(void)
diff --git a/firmware/export/ascodec.h b/firmware/export/ascodec.h
index c2ff3c8242..b9c58c08ba 100644
--- a/firmware/export/ascodec.h
+++ b/firmware/export/ascodec.h
@@ -43,6 +43,8 @@ int ascodec_read(unsigned int index);
43 43
44void ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data); 44void ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data);
45 45
46void ascodec_wait_adc_finished(void);
47
46#if CONFIG_CHARGING 48#if CONFIG_CHARGING
47bool ascodec_endofch(void); 49bool ascodec_endofch(void);
48bool ascodec_chg_status(void); 50bool ascodec_chg_status(void);
diff --git a/firmware/export/system.h b/firmware/export/system.h
index 49249f6bb5..050c3074aa 100644
--- a/firmware/export/system.h
+++ b/firmware/export/system.h
@@ -51,10 +51,6 @@ bool detect_original_firmware(void);
51#endif 51#endif
52 52
53#ifdef HAVE_ADJUSTABLE_CPU_FREQ 53#ifdef HAVE_ADJUSTABLE_CPU_FREQ
54#if NUM_CORES > 1
55extern struct spinlock boostctrl_spin;
56#endif
57void cpu_boost_init(void);
58#define FREQ cpu_frequency 54#define FREQ cpu_frequency
59void set_cpu_frequency(long frequency); 55void set_cpu_frequency(long frequency);
60#ifdef CPU_BOOST_LOGGING 56#ifdef CPU_BOOST_LOGGING
@@ -214,6 +210,17 @@ enum {
214#define CPU_MODE_THREAD_CONTEXT 0 210#define CPU_MODE_THREAD_CONTEXT 0
215#endif 211#endif
216 212
213#ifdef HAVE_ADJUSTABLE_CPU_FREQ
214#ifndef CPU_BOOST_LOCK_DEFINED
215#define CPU_BOOST_LOCK_DEFINED
216/* Compatibility defauls */
217static inline bool cpu_boost_lock(void)
218 { return true; }
219static inline void cpu_boost_unlock(void)
220 { }
221#endif /* CPU_BOOST_LOCK */
222#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
223
217#ifndef BIT_N 224#ifndef BIT_N
218#define BIT_N(n) (1U << (n)) 225#define BIT_N(n) (1U << (n))
219#endif 226#endif
diff --git a/firmware/panic.c b/firmware/panic.c
index 7b2c79a872..a35291636d 100644
--- a/firmware/panic.c
+++ b/firmware/panic.c
@@ -127,7 +127,13 @@ void panicf( const char *fmt, ...)
127 lcd_update(); 127 lcd_update();
128 DEBUGF("%s", panic_buf); 128 DEBUGF("%s", panic_buf);
129 129
130 set_cpu_frequency(0); 130#ifdef HAVE_ADJUSTABLE_CPU_FREQ
131 if (cpu_boost_lock())
132 {
133 set_cpu_frequency(0);
134 cpu_boost_unlock();
135 }
136#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
131 137
132#ifdef HAVE_ATA_POWER_OFF 138#ifdef HAVE_ATA_POWER_OFF
133 ide_power_enable(false); 139 ide_power_enable(false);
diff --git a/firmware/system.c b/firmware/system.c
index 37631b8735..537e901b05 100644
--- a/firmware/system.c
+++ b/firmware/system.c
@@ -35,13 +35,6 @@ long cpu_frequency SHAREDBSS_ATTR = CPU_FREQ;
35#ifdef HAVE_ADJUSTABLE_CPU_FREQ 35#ifdef HAVE_ADJUSTABLE_CPU_FREQ
36static int boost_counter SHAREDBSS_ATTR = 0; 36static int boost_counter SHAREDBSS_ATTR = 0;
37static bool cpu_idle SHAREDBSS_ATTR = false; 37static bool cpu_idle SHAREDBSS_ATTR = false;
38#if NUM_CORES > 1
39static struct corelock boostctrl_cl SHAREDBSS_ATTR;
40void cpu_boost_init(void)
41{
42 corelock_init(&boostctrl_cl);
43}
44#endif
45 38
46int get_cpu_boost_counter(void) 39int get_cpu_boost_counter(void)
47{ 40{
@@ -60,7 +53,7 @@ int cpu_boost_log_getcount(void)
60char * cpu_boost_log_getlog_first(void) 53char * cpu_boost_log_getlog_first(void)
61{ 54{
62 char *first; 55 char *first;
63 corelock_lock(&boostctrl_cl); 56 cpu_boost_lock();
64 57
65 first = NULL; 58 first = NULL;
66 59
@@ -70,7 +63,7 @@ char * cpu_boost_log_getlog_first(void)
70 first = cpu_boost_calls[cpu_boost_first]; 63 first = cpu_boost_calls[cpu_boost_first];
71 } 64 }
72 65
73 corelock_unlock(&boostctrl_cl); 66 cpu_boost_unlock();
74 return first; 67 return first;
75} 68}
76 69
@@ -79,7 +72,7 @@ char * cpu_boost_log_getlog_next(void)
79 int message; 72 int message;
80 char *next; 73 char *next;
81 74
82 corelock_lock(&boostctrl_cl); 75 cpu_boost_lock();
83 76
84 message = (cpu_boost_track_message+cpu_boost_first)%MAX_BOOST_LOG; 77 message = (cpu_boost_track_message+cpu_boost_first)%MAX_BOOST_LOG;
85 next = NULL; 78 next = NULL;
@@ -90,13 +83,14 @@ char * cpu_boost_log_getlog_next(void)
90 next = cpu_boost_calls[message]; 83 next = cpu_boost_calls[message];
91 } 84 }
92 85
93 corelock_unlock(&boostctrl_cl); 86 cpu_boost_unlock();
94 return next; 87 return next;
95} 88}
96 89
97void cpu_boost_(bool on_off, char* location, int line) 90void cpu_boost_(bool on_off, char* location, int line)
98{ 91{
99 corelock_lock(&boostctrl_cl); 92 if (!cpu_boost_lock())
93 return;
100 94
101 if (cpu_boost_calls_count == MAX_BOOST_LOG) 95 if (cpu_boost_calls_count == MAX_BOOST_LOG)
102 { 96 {
@@ -115,7 +109,9 @@ void cpu_boost_(bool on_off, char* location, int line)
115#else 109#else
116void cpu_boost(bool on_off) 110void cpu_boost(bool on_off)
117{ 111{
118 corelock_lock(&boostctrl_cl); 112 if (!cpu_boost_lock())
113 return;
114
119#endif /* CPU_BOOST_LOGGING */ 115#endif /* CPU_BOOST_LOGGING */
120 if(on_off) 116 if(on_off)
121 { 117 {
@@ -141,12 +137,13 @@ void cpu_boost(bool on_off)
141 } 137 }
142 } 138 }
143 139
144 corelock_unlock(&boostctrl_cl); 140 cpu_boost_unlock();
145} 141}
146 142
147void cpu_idle_mode(bool on_off) 143void cpu_idle_mode(bool on_off)
148{ 144{
149 corelock_lock(&boostctrl_cl); 145 if (!cpu_boost_lock())
146 return;
150 147
151 cpu_idle = on_off; 148 cpu_idle = on_off;
152 149
@@ -160,7 +157,7 @@ void cpu_idle_mode(bool on_off)
160 set_cpu_frequency(CPUFREQ_NORMAL); 157 set_cpu_frequency(CPUFREQ_NORMAL);
161 } 158 }
162 159
163 corelock_unlock(&boostctrl_cl); 160 cpu_boost_unlock();
164} 161}
165#endif /* HAVE_ADJUSTABLE_CPU_FREQ */ 162#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
166 163
diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c
index ec25a415a5..e144f07ed4 100644
--- a/firmware/target/arm/as3525/ascodec-as3525.c
+++ b/firmware/target/arm/as3525/ascodec-as3525.c
@@ -50,7 +50,7 @@
50#include "system.h" 50#include "system.h"
51#include "as3525.h" 51#include "as3525.h"
52#include "i2c.h" 52#include "i2c.h"
53#include "logf.h" 53#include <linked_list.h>
54 54
55#define I2C2_DATA *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x00)) 55#define I2C2_DATA *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x00))
56#define I2C2_SLAD0 *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x04)) 56#define I2C2_SLAD0 *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x04))
@@ -78,234 +78,495 @@
78#define I2C2_IRQ_RXOVER 0x10 78#define I2C2_IRQ_RXOVER 0x10
79#define I2C2_IRQ_ACKTIMEO 0x80 79#define I2C2_IRQ_ACKTIMEO 0x80
80 80
81#define REQ_UNFINISHED 0
82#define REQ_FINISHED 1
83#define REQ_RETRY 2
81 84
82static struct mutex as_mtx; 85#ifdef DEBUG
83 86#define IFDEBUG(x) x
84#if CONFIG_CHARGING 87#else
85static bool chg_status = false; 88#define IFDEBUG(x)
86static bool endofch = false;
87#endif 89#endif
88 90
89/* returns true when busy */ 91#define ASCODEC_REQ_READ 0
90static inline bool i2c_busy(void) 92#define ASCODEC_REQ_WRITE 1
93
94/*
95 * How many bytes we using in struct ascodec_request for the data buffer.
96 * 4 fits the alignment best right now.
97 * We don't actually use more than 3 at the moment (when reading interrupts)
98 * Upper limit would be 255 since DACNT is 8 bits!
99 */
100#define ASCODEC_REQ_MAXLEN 4
101
102struct ascodec_request;
103typedef void (ascodec_cb_fn)(struct ascodec_request *req);
104
105struct ascodec_request {
106 /* standard request members */
107 struct ll_node node; /* request list link (first!) */
108 unsigned char type; /* reqest type (read or write) */
109 unsigned char index; /* initial i2c sub address */
110 unsigned char cnt; /* bytes remaining */
111 unsigned char data[ASCODEC_REQ_MAXLEN]; /* actual I/O data */
112
113 /* members relevant when a callback is specified (callback != NULL) */
114 ascodec_cb_fn *callback; /* pointer to callback function */
115 intptr_t cbdata; /* data for callback function */
116 int len_done; /* amount actually transferred */
117};
118
119/* I2C driver data */
120static struct mutex as_mtx;
121static struct ll_head req_list;
122static unsigned char *req_data_ptr;
123#define REQ_FIRST ((struct ascodec_request *)req_list.head)
124
125/* INT_AUDIO interrupt data */
126static void ascodec_int_audio_cb(struct ascodec_request *req);
127void INT_I2C_AUDIO(void);
128static struct ascodec_request as_audio_req;
129static struct semaphore adc_done_sem;
130static unsigned long ascodec_enrd0_shadow = 0;
131
132static void ascodec_wait_cb(struct ascodec_request *req);
133
134/** --debugging help-- **/
135
136#ifdef DEBUG
137/* counters for debugging INT_AUDIO */
138static struct int_audio_counters {
139 int int_audio;
140 int int_chg_finished;
141 int int_chg_insert;
142 int int_chg_remove;
143 int int_usb_insert;
144 int int_usb_remove;
145 int int_rtc;
146 int int_adc;
147} int_audio_counters;
148#endif /* DEBUG */
149
150#define COUNT_INT(x) IFDEBUG((int_audio_counters.int_##x)++)
151
152
153/** --stock request and callback functionality -- **/
154
155/* init for common request data (call before submitting) */
156static inline void ascodec_req_init(struct ascodec_request *req, int type,
157 unsigned int index, unsigned int cnt)
91{ 158{
92 return (I2C2_SR & 1); 159 req->type = type;
160 req->index = index;
161 req->cnt = cnt;
93} 162}
94 163
95void i2c_init(void) 164/* stock no-wait init for request (use any callback and data) */
165static inline void ascodec_async_init(struct ascodec_request *req,
166 ascodec_cb_fn *callback, intptr_t cbdata)
96{ 167{
168 /* cbdata is unused if no callback is used */
169 if ((req->callback = callback))
170 req->cbdata = cbdata;
97} 171}
98 172
99static void i2c2_init(void) 173/* initialize the stock completion callback */
174static inline void ascodec_wait_init(struct ascodec_request *req,
175 struct semaphore *completep)
100{ 176{
101 int prescaler; 177 req->callback = ascodec_wait_cb;
102 178 req->cbdata = (intptr_t)completep;
103 /* prescaler for i2c clock */ 179 semaphore_init(completep, 1, 0);
104 prescaler = AS3525_I2C_PRESCALER; 180}
105 I2C2_CPSR0 = prescaler & 0xFF; /* 8 lsb */
106 I2C2_CPSR1 = (prescaler >> 8) & 0x3; /* 2 msb */
107 181
108 /* set i2c slave address of codec part */ 182/* caller waits here when using ascodec_wait_cb to do synchronous transfers */
109 I2C2_SLAD0 = AS3514_I2C_ADDR << 1; 183static void ascodec_wait(struct ascodec_request *req)
184{
185 struct semaphore *completep = (struct semaphore *)req->cbdata;
186 int timeout = TIMEOUT_BLOCK;
110 187
111 I2C2_CNTRL = I2C2_CNTRL_DEFAULT; 188 if (!irq_enabled() || !is_thread_context()) {
189 timeout = TIMEOUT_NOBLOCK; /* poll semaphore, no block */
190 }
112 191
192 while (semaphore_wait(completep, timeout) == OBJ_WAIT_TIMEDOUT) {
193 /* pump the i2c interrupts ourselves (only waiting can do this!) */
194 if (I2C2_MIS) {
195 INT_I2C_AUDIO();
196 }
197 }
113} 198}
114 199
115/* initialises the internal i2c bus and prepares for transfers to the codec */ 200/* stock callback used in order to wait for a transfer to complete */
116void ascodec_init(void) 201static void ascodec_wait_cb(struct ascodec_request *req)
117{ 202{
203 struct semaphore *completep = (struct semaphore *)req->cbdata;
204 semaphore_release(completep);
205}
118 206
119 mutex_init(&as_mtx); 207
208/**-- I2C2 interrupt handling --**/
209
210/* start the controller on the next transfer */
211static void ascodec_start_req(struct ascodec_request *req)
212{
213 int unmask = 0;
120 214
121 /* enable clock */ 215 /* enable clock */
122 bitset32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE); 216 bitset32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE);
123 217
124 i2c2_init(); 218 /* start transfer */
219 I2C2_SADDR = req->index;
220
221 if (req->type == ASCODEC_REQ_READ) {
222 req_data_ptr = req->data;
223 I2C2_CNTRL = I2C2_CNTRL_DEFAULT | I2C2_CNTRL_READ;
224 unmask = I2C2_IRQ_RXFULL|I2C2_IRQ_RXOVER;
225 } else {
226 req_data_ptr = &req->data[1];
227 I2C2_CNTRL = I2C2_CNTRL_DEFAULT | I2C2_CNTRL_WRITE;
228 I2C2_DATA = req->data[0];
229 unmask = I2C2_IRQ_TXEMPTY|I2C2_IRQ_ACKTIMEO;
230 }
125 231
126 /* Generate irq for usb+charge status change */ 232 I2C2_DACNT = req->cnt;
127 ascodec_write(AS3514_IRQ_ENRD0, 233 I2C2_IMR |= unmask; /* enable interrupts */
128#if CONFIG_CHARGING /* m200v4 can't charge */ 234}
129 IRQ_CHGSTAT | IRQ_ENDOFCH |
130#endif
131 IRQ_USBSTAT);
132 235
133#if CONFIG_CPU == AS3525v2 236/* send the next bytes or read bytes received */
134 /* XIRQ = IRQ, active low reset signal, 6mA push-pull output */ 237static int ascodec_continue_req(struct ascodec_request *req, int irq_status)
135 ascodec_write_pmu(0x1a, 3, (1<<2)|3); /* 1A-3 = Out_Cntr3 register */ 238{
136 /* reset for compatible with old bootloader */ 239 if ((irq_status & (I2C2_IRQ_RXOVER|I2C2_IRQ_ACKTIMEO)) > 0) {
137 ascodec_write(AS3514_IRQ_ENRD2, 0x0); 240 /* some error occured, restart the request */
138#else 241 return REQ_RETRY;
139 /* Generate irq for push-pull, active high, irq on rtc+adc change */ 242 }
140 ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE);
141#endif
142 243
143 VIC_INT_ENABLE = INTERRUPT_AUDIO; 244 if (req->type == ASCODEC_REQ_READ &&
245 (irq_status & I2C2_IRQ_RXFULL) > 0) {
246 *req_data_ptr++ = I2C2_DATA;
247 } else {
248 if (req->cnt > 1 &&
249 (irq_status & I2C2_IRQ_TXEMPTY) > 0) {
250 I2C2_DATA = *req_data_ptr++;
251 }
252 }
144 253
145 /* detect if USB was connected at startup since there is no transition */ 254 req->index++;
146 int data = ascodec_read(AS3514_IRQ_ENRD0); 255 if (--req->cnt > 0)
256 return REQ_UNFINISHED;
147 257
148 if(data & USB_STATUS) 258 return REQ_FINISHED;
149 usb_insert_int(); 259}
150 260
151#if CONFIG_CHARGING 261/* complete the request and call the completion callback, if any */
152 chg_status = data & CHG_STATUS; 262static void ascodec_finish_req(struct ascodec_request *req)
153#endif 263{
264 /*
265 * Wait if still busy, unfortunately this happens since
266 * the controller is running at a low divisor, so it's
267 * still busy when we serviced the interrupt.
268 * I tried upping the i2c speed to 4MHz which
269 * made the number of busywait cycles much smaller
270 * (none for reads and only a few for writes),
271 * but who knows if it's reliable at that frequency. ;)
272 * For one thing, 8MHz doesn't work, so 4MHz is likely
273 * borderline.
274 * In general writes need much more wait cycles than reads
275 * for some reason, possibly because we read the data register
276 * for reads, which will likely block the processor while
277 * the i2c controller responds to the register read.
278 */
279 while (I2C2_SR & 1);
280
281 if (req->callback) {
282 req->len_done = req_data_ptr - req->data;
283 req->callback(req);
284 }
154} 285}
155 286
156/* returns false if transfer incomplete */ 287/* ISR for I2C2 */
157static bool i2c2_transfer(void) 288void INT_I2C_AUDIO(void)
158{ 289{
159 static int try = 0; 290 struct ascodec_request *req = REQ_FIRST;
160 291
161 /* wait for transfer*/ 292 int irq_status = I2C2_MIS;
162 int i = 10000; 293 int status = ascodec_continue_req(req, irq_status);
163 while (I2C2_DACNT != 0 && i--);
164 294
165 if (!i) { 295 I2C2_INT_CLR = irq_status; /* clear interrupt status */
166 if (try == 5)
167 panicf("I2C2 reset failed");
168 296
169 logf("reset I2C2 %d", try); 297 if (status != REQ_UNFINISHED) {
298 /* mask rx/tx interrupts */
299 I2C2_IMR &= ~(I2C2_IRQ_TXEMPTY|I2C2_IRQ_RXFULL|
300 I2C2_IRQ_RXOVER|I2C2_IRQ_ACKTIMEO);
170 301
171 i2c2_init(); 302 if (status == REQ_FINISHED)
303 ascodec_finish_req(req);
172 304
173 try++; 305 int oldlevel = disable_irq_save(); /* IRQs are stacked */
174 return false; 306
175 } 307 /*
308 * If status == REQ_RETRY, this will restart the request from where
309 * it left off because we didn't remove it from the request list
310 */
176 311
177 try = 0; 312 if (status == REQ_FINISHED) {
178 return true; 313 ll_remove_next(&req_list, NULL);
314 }
315
316 req = REQ_FIRST;
317 if (req == NULL) {
318 /* disable clock */
319 bitclr32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE);
320 } else {
321 ascodec_start_req(req);
322 }
323
324 restore_irq(oldlevel);
325 }
179} 326}
180 327
181void ascodec_write(unsigned int index, unsigned int value) 328
329/** --Routines for reading and writing data on the bus-- **/
330
331/* add the request to the queue */
332static void ascodec_submit(struct ascodec_request *req)
182{ 333{
183 ascodec_lock(); 334 int oldlevel = disable_irq_save();
335
336 ll_insert_last(&req_list, &req->node);
337
338 if (REQ_FIRST == req) {
339 /* first on list? start driver */
340 ascodec_start_req(req);
341 }
342
343 restore_irq(oldlevel);
344}
184 345
346/*
347 * The request struct passed in must be allocated statically.
348 * If you call ascodec_async_write from different places, each
349 * call needs it's own request struct.
350 */
351static void ascodec_async_write(struct ascodec_request *req,
352 unsigned int index, unsigned int value)
353{
185#ifndef HAVE_AS3543 354#ifndef HAVE_AS3543
186 if (index == AS3514_CVDD_DCDC3) /* prevent setting of the LREG_CP_not bit */ 355 if (index == AS3514_CVDD_DCDC3) /* prevent setting of the LREG_CP_not bit */
187 value &= ~(1 << 5); 356 value &= ~(1 << 5);
188#endif 357#endif
189 358
190 do { 359 ascodec_req_init(req, ASCODEC_REQ_WRITE, index, 1);
191 /* wait if still busy */ 360 req->data[0] = value;
192 while (i2c_busy()); 361 ascodec_submit(req);
362}
363
364void ascodec_write(unsigned int index, unsigned int value)
365{
366 struct ascodec_request req;
367 struct semaphore complete;
193 368
194 /* start transfer */ 369 ascodec_wait_init(&req, &complete);
195 I2C2_SADDR = index; 370 ascodec_async_write(&req, index, value);
196 I2C2_CNTRL &= ~(1 << 1); 371 ascodec_wait(&req);
197 I2C2_DATA = value; 372}
198 I2C2_DACNT = 1;
199 373
200 } while (!i2c2_transfer()); 374/*
375 * The request struct passed in must be allocated statically.
376 * If you call ascodec_async_read from different places, each
377 * call needs it's own request struct.
378 * If len is bigger than ASCODEC_REQ_MAXLEN it will be
379 * set to ASCODEC_REQ_MAXLEN.
380 */
381static void ascodec_async_read(struct ascodec_request *req,
382 unsigned int index, unsigned int len)
383{
384 if (len > ASCODEC_REQ_MAXLEN)
385 len = ASCODEC_REQ_MAXLEN; /* can't fit more in one request */
201 386
202 ascodec_unlock(); 387 ascodec_req_init(req, ASCODEC_REQ_READ, index, len);
388 ascodec_submit(req);
203} 389}
204 390
391/* read data synchronously */
205int ascodec_read(unsigned int index) 392int ascodec_read(unsigned int index)
206{ 393{
207 int data; 394 struct ascodec_request req;
395 struct semaphore complete;
208 396
209 ascodec_lock(); 397 ascodec_wait_init(&req, &complete);
398 ascodec_async_read(&req, index, 1);
399 ascodec_wait(&req);
210 400
211 do { 401 return req.data[0];
212 /* wait if still busy */ 402}
213 while (i2c_busy());
214 403
215 /* start transfer */ 404/* read an array of bytes */
216 I2C2_SADDR = index; 405void ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data)
217 I2C2_CNTRL |= (1 << 1); 406{
218 I2C2_DACNT = 1; 407 struct ascodec_request req;
408 struct semaphore complete;
219 409
220 } while (!i2c2_transfer()); 410 ascodec_wait_init(&req, &complete);
221 411
222 data = I2C2_DATA; 412 /* index and cnt will be filled in later, just use 0 */
413 ascodec_req_init(&req, ASCODEC_REQ_READ, 0, 0);
223 414
224 ascodec_unlock(); 415 int i = 0;
225 416
226 return data; 417 while (len > 0) {
227} 418 int cnt = MIN(len, ASCODEC_REQ_MAXLEN);
228 419
229void ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data) 420 req.index = index;
230{ 421 req.cnt = cnt;
231 unsigned int i; 422
423 ascodec_submit(&req);
424 ascodec_wait(&req);
425
426 for (int j = 0; j < cnt; j++)
427 data[i++] = req.data[j];
232 428
233 for(i = 0; i < len; i++) 429 len -= cnt;
234 data[i] = ascodec_read(index+i); 430 index += cnt;
431 }
235} 432}
236 433
237#if CONFIG_CPU == AS3525v2 434#if CONFIG_CPU == AS3525v2
435/* write special PMU subregisters */
238void ascodec_write_pmu(unsigned int index, unsigned int subreg, 436void ascodec_write_pmu(unsigned int index, unsigned int subreg,
239 unsigned int value) 437 unsigned int value)
240{ 438{
241 ascodec_lock(); 439 struct ascodec_request reqs[2];
440 struct semaphore complete;
441
442 ascodec_async_init(&reqs[0], NULL, 0);
443 ascodec_wait_init(&reqs[1], &complete);
444
445 int oldstatus = disable_irq_save();
242 /* we submit consecutive requests to make sure no operations happen on the 446 /* we submit consecutive requests to make sure no operations happen on the
243 * i2c bus between selecting the sub register and writing to it */ 447 * i2c bus between selecting the sub register and writing to it */
244 ascodec_write(AS3543_PMU_ENABLE, 8 | subreg); 448 ascodec_async_write(&reqs[0], AS3543_PMU_ENABLE, 8 | subreg);
245 ascodec_write(index, value); 449 ascodec_async_write(&reqs[1], index, value);
450 restore_irq(oldstatus);
246 451
247 ascodec_unlock(); 452 /* Wait for second request to finish */
453 ascodec_wait(&reqs[1]);
248} 454}
249 455
456/* read special PMU subregisters */
250int ascodec_read_pmu(unsigned int index, unsigned int subreg) 457int ascodec_read_pmu(unsigned int index, unsigned int subreg)
251{ 458{
252 ascodec_lock(); 459 struct ascodec_request reqs[2];
460 struct semaphore complete;
461
462 ascodec_async_init(&reqs[0], NULL, 0);
463 ascodec_wait_init(&reqs[1], &complete);
464
465 int oldstatus = disable_irq_save();
253 /* we submit consecutive requests to make sure no operations happen on the 466 /* we submit consecutive requests to make sure no operations happen on the
254 * i2c bus between selecting the sub register and reading it */ 467 * i2c bus between selecting the sub register and reading it */
255 ascodec_write(AS3543_PMU_ENABLE, subreg); 468 ascodec_async_write(&reqs[0], AS3543_PMU_ENABLE, subreg);
256 int ret = ascodec_read(index); 469 ascodec_async_read(&reqs[1], index, 1);
470 restore_irq(oldstatus);
257 471
258 ascodec_unlock(); 472 /* Wait for second request to finish */
473 ascodec_wait(&reqs[1]);
259 474
260 return ret; 475 return reqs[1].data[0];
261} 476}
262#endif /* CONFIG_CPU == AS3525v2 */ 477#endif /* CONFIG_CPU == AS3525v2 */
263 478
264void INT_AUDIO(void) 479/* callback that receives results of reading INT_AUDIO status register */
480static void ascodec_int_audio_cb(struct ascodec_request *req)
265{ 481{
266 int oldstatus = disable_irq_save(); 482 unsigned char * const data = req->data;
267 int data = ascodec_read(AS3514_IRQ_ENRD0);
268 483
269#if CONFIG_CHARGING 484 if (UNLIKELY(req->len_done != 3)) { /* some error happened? */
270 if (data & CHG_ENDOFCH) { /* chg finished */ 485 panicf("INT_AUDIO callback got %d regs", req->len_done);
271 endofch = true;
272 } 486 }
273 487
274 chg_status = data & CHG_STATUS; 488 if (data[0] & CHG_ENDOFCH) { /* chg finished */
275#endif 489 COUNT_INT(chg_finished);
490 ascodec_enrd0_shadow |= CHG_ENDOFCH;
491 }
492
493 if (data[0] & CHG_CHANGED) { /* chg status changed */
494 if (data[0] & CHG_STATUS) {
495 COUNT_INT(chg_insert);
496 ascodec_enrd0_shadow |= CHG_STATUS;
497 } else {
498 COUNT_INT(chg_remove);
499 ascodec_enrd0_shadow &= ~CHG_STATUS;
500 }
501 }
276 502
277 if (data & USB_CHANGED) { /* usb status changed */ 503 if (data[0] & USB_CHANGED) { /* usb status changed */
278 if (data & USB_STATUS) { 504 if (data[0] & USB_STATUS) {
505 COUNT_INT(usb_insert);
279 usb_insert_int(); 506 usb_insert_int();
280 } else { 507 } else {
508 COUNT_INT(usb_remove);
281 usb_remove_int(); 509 usb_remove_int();
282 } 510 }
283 } 511 }
284 512
285 restore_irq(oldstatus); 513 if (data[2] & IRQ_RTC) { /* rtc irq */
514 /*
515 * Can be configured for once per second or once per minute,
516 * default is once per second
517 */
518 COUNT_INT(rtc);
519 }
520
521 if (data[2] & IRQ_ADC) { /* adc finished */
522 COUNT_INT(adc);
523 semaphore_release(&adc_done_sem);
524 }
525
526 VIC_INT_ENABLE = INTERRUPT_AUDIO;
527}
528
529/* ISR for all various ascodec events */
530void INT_AUDIO(void)
531{
532 VIC_INT_EN_CLEAR = INTERRUPT_AUDIO;
533 COUNT_INT(audio);
534
535 ascodec_async_read(&as_audio_req, AS3514_IRQ_ENRD0, 3);
536}
537
538/* wait for ADC to finish conversion */
539void ascodec_wait_adc_finished(void)
540{
541 semaphore_wait(&adc_done_sem, TIMEOUT_BLOCK);
286} 542}
287 543
288#if CONFIG_CHARGING 544#if CONFIG_CHARGING
545/* read sticky end-of-charge bit and clear it */
289bool ascodec_endofch(void) 546bool ascodec_endofch(void)
290{ 547{
291 int oldstatus = disable_irq_save(); 548 int oldlevel = disable_irq_save();
292 bool ret = endofch; 549
293 endofch = false; 550 bool ret = ascodec_enrd0_shadow & CHG_ENDOFCH;
294 restore_irq(oldstatus); 551 ascodec_enrd0_shadow &= ~CHG_ENDOFCH; /* clear interrupt */
552
553 restore_irq(oldlevel);
295 554
296 return ret; 555 return ret;
297} 556}
298 557
558/* read the presence state of the charger */
299bool ascodec_chg_status(void) 559bool ascodec_chg_status(void)
300{ 560{
301 return chg_status; 561 return ascodec_enrd0_shadow & CHG_STATUS;
302} 562}
303 563
304void ascodec_monitor_endofch(void) 564void ascodec_monitor_endofch(void)
305{ 565{
306 /* already enabled */ 566 /* end of charge status interrupt already enabled */
307} 567}
308 568
569/* write charger control register */
309void ascodec_write_charger(int value) 570void ascodec_write_charger(int value)
310{ 571{
311#if CONFIG_CPU == AS3525 572#if CONFIG_CPU == AS3525
@@ -315,6 +576,7 @@ void ascodec_write_charger(int value)
315#endif 576#endif
316} 577}
317 578
579/* read charger control register */
318int ascodec_read_charger(void) 580int ascodec_read_charger(void)
319{ 581{
320#if CONFIG_CPU == AS3525 582#if CONFIG_CPU == AS3525
@@ -325,6 +587,15 @@ int ascodec_read_charger(void)
325} 587}
326#endif /* CONFIG_CHARGING */ 588#endif /* CONFIG_CHARGING */
327 589
590/*
591 * NOTE:
592 * After the conversion to interrupts, ascodec_(lock|unlock) are only used by
593 * adc-as3514.c to protect against other threads corrupting the result by using
594 * the ADC at the same time.
595 * Concurrent ascodec_(async_)?(read|write) calls are instead protected
596 * because ascodec_submit() is atomic and concurrent requests will wait
597 * in the queue until the current request is finished.
598 */
328void ascodec_lock(void) 599void ascodec_lock(void)
329{ 600{
330 mutex_lock(&as_mtx); 601 mutex_lock(&as_mtx);
@@ -334,3 +605,63 @@ void ascodec_unlock(void)
334{ 605{
335 mutex_unlock(&as_mtx); 606 mutex_unlock(&as_mtx);
336} 607}
608
609
610/** --Startup initialization-- **/
611
612void i2c_init(void)
613{
614 /* required function but called too late for our needs */
615}
616
617/* initialises the internal i2c bus and prepares for transfers to the codec */
618void ascodec_init(void)
619{
620 int prescaler;
621
622 ll_init(&req_list);
623 mutex_init(&as_mtx);
624 ascodec_async_init(&as_audio_req, ascodec_int_audio_cb, 0);
625 semaphore_init(&adc_done_sem, 1, 0);
626
627 /* enable clock */
628 bitset32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE);
629
630 /* prescaler for i2c clock */
631 prescaler = AS3525_I2C_PRESCALER;
632 I2C2_CPSR0 = prescaler & 0xFF; /* 8 lsb */
633 I2C2_CPSR1 = (prescaler >> 8) & 0x3; /* 2 msb */
634
635 /* set i2c slave address of codec part */
636 I2C2_SLAD0 = AS3514_I2C_ADDR << 1;
637
638 I2C2_CNTRL = I2C2_CNTRL_DEFAULT;
639
640 I2C2_IMR = 0x00; /* disable interrupts */
641 I2C2_INT_CLR = I2C2_RIS; /* clear interrupt status */
642 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO;
643 VIC_INT_ENABLE = INTERRUPT_AUDIO;
644
645 /* detect if USB was connected at startup since there is no transition */
646 ascodec_enrd0_shadow = ascodec_read(AS3514_IRQ_ENRD0);
647 if(ascodec_enrd0_shadow & USB_STATUS)
648 usb_insert_int();
649
650 /* Generate irq for usb+charge status change */
651 ascodec_write(AS3514_IRQ_ENRD0,
652#if CONFIG_CHARGING /* m200v4 can't charge */
653 IRQ_CHGSTAT | IRQ_ENDOFCH |
654#endif
655 IRQ_USBSTAT);
656
657#if CONFIG_CPU == AS3525v2
658 /* XIRQ = IRQ, active low reset signal, 6mA push-pull output */
659 ascodec_write_pmu(0x1a, 3, (1<<2)|3); /* 1A-3 = Out_Cntr3 register */
660 /* Generate irq on (rtc,) adc change */
661 ascodec_write(AS3514_IRQ_ENRD2, /*IRQ_RTC |*/ IRQ_ADC);
662#else
663 /* Generate irq for push-pull, active high, irq on rtc+adc change */
664 ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE |
665 /*IRQ_RTC |*/ IRQ_ADC);
666#endif
667}
diff --git a/firmware/target/arm/as3525/debug-as3525.c b/firmware/target/arm/as3525/debug-as3525.c
index 1ee4de64cc..a1e69834dd 100644
--- a/firmware/target/arm/as3525/debug-as3525.c
+++ b/firmware/target/arm/as3525/debug-as3525.c
@@ -605,3 +605,33 @@ end:
605 lcd_setfont(FONT_UI); 605 lcd_setfont(FONT_UI);
606 return false; 606 return false;
607} 607}
608
609#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
610/* Return CPU voltage setting in millivolts */
611int get_cpu_voltage_setting(void)
612{
613 int value;
614
615#if CONFIG_CPU == AS3525
616 value = ascodec_read(AS3514_CVDD_DCDC3) & 0x3;
617 value = 1200 - value * 50;
618#else /* as3525v2 */
619 value = ascodec_read_pmu(0x17, 1) & 0x7f;
620
621 /* Calculate in 0.1mV steps */
622 if (value == 0)
623 /* 0 volts */;
624 else if (value <= 0x40)
625 value = 6000 + value * 125;
626 else if (value <= 0x70)
627 value = 14000 + (value - 0x40) * 250;
628 else if (value <= 0x7f)
629 value = 26000 + (value - 0x70) * 500;
630
631 /* Return voltage setting in millivolts */
632 value = (value + 5) / 10;
633#endif /* CONFIG_CPU */
634
635 return value;
636}
637#endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */
diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c
index 8aa2d02ab7..0ea0c8fba4 100644
--- a/firmware/target/arm/as3525/system-as3525.c
+++ b/firmware/target/arm/as3525/system-as3525.c
@@ -33,6 +33,8 @@
33#include "backlight-target.h" 33#include "backlight-target.h"
34#include "lcd.h" 34#include "lcd.h"
35 35
36struct mutex cpufreq_mtx;
37
36/* Charge Pump and Power management Settings */ 38/* Charge Pump and Power management Settings */
37#define AS314_CP_DCDC3_SETTING \ 39#define AS314_CP_DCDC3_SETTING \
38 ((0<<7) | /* CP_SW Auto-Switch Margin 0=200/300 1=150/255 */ \ 40 ((0<<7) | /* CP_SW Auto-Switch Margin 0=200/300 1=150/255 */ \
@@ -144,6 +146,7 @@ static const struct { int source; void (*isr) (void); } vec_int_srcs[] =
144 { INT_SRC_USB, INT_USB_FUNC, }, 146 { INT_SRC_USB, INT_USB_FUNC, },
145 { INT_SRC_TIMER1, INT_TIMER1 }, 147 { INT_SRC_TIMER1, INT_TIMER1 },
146 { INT_SRC_TIMER2, INT_TIMER2 }, 148 { INT_SRC_TIMER2, INT_TIMER2 },
149 { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO },
147 { INT_SRC_AUDIO, INT_AUDIO }, 150 { INT_SRC_AUDIO, INT_AUDIO },
148 /* Lowest priority at the end of the list */ 151 /* Lowest priority at the end of the list */
149}; 152};
@@ -322,6 +325,12 @@ void system_init(void)
322 setup_vic(); 325 setup_vic();
323 326
324 dma_init(); 327 dma_init();
328}
329
330/* this is called after kernel and threading are initialized */
331void kernel_device_init(void)
332{
333 mutex_init(&cpufreq_mtx);
325 334
326 ascodec_init(); 335 ascodec_init();
327 336
@@ -329,7 +338,8 @@ void system_init(void)
329#ifdef HAVE_AS3543 338#ifdef HAVE_AS3543
330 /* PLL: disable audio PLL, we use MCLK already */ 339 /* PLL: disable audio PLL, we use MCLK already */
331 ascodec_write_pmu(0x1A, 7, 0x02); 340 ascodec_write_pmu(0x1A, 7, 0x02);
332 /* DCDC_Cntr: set switching speed of CVDD1/2 power supplies to 1 MHz */ 341 /* DCDC_Cntr: set switching speed of CVDD1/2 power supplies to 1 MHz,
342 immediate change */
333 ascodec_write_pmu(0x17, 7, 0x30); 343 ascodec_write_pmu(0x17, 7, 0x30);
334 /* Out_Cntr2: set drive strength of 24 MHz and 32 kHz clocks to 1 mA */ 344 /* Out_Cntr2: set drive strength of 24 MHz and 32 kHz clocks to 1 mA */
335 ascodec_write_pmu(0x1A, 2, 0xCC); 345 ascodec_write_pmu(0x1A, 2, 0xCC);
@@ -414,11 +424,28 @@ void udelay(unsigned usecs)
414 424
415#ifndef BOOTLOADER 425#ifndef BOOTLOADER
416#ifdef HAVE_ADJUSTABLE_CPU_FREQ 426#ifdef HAVE_ADJUSTABLE_CPU_FREQ
427bool set_cpu_frequency__lock(void)
428{
429 if (get_processor_mode() != CPU_MODE_THREAD_CONTEXT)
430 return false;
431
432 mutex_lock(&cpufreq_mtx);
433 return true;
434}
435
436void set_cpu_frequency__unlock(void)
437{
438 mutex_unlock(&cpufreq_mtx);
439}
417 440
418#if CONFIG_CPU == AS3525 441#if CONFIG_CPU == AS3525
419void set_cpu_frequency(long frequency) 442void set_cpu_frequency(long frequency)
420{ 443{
421 if(frequency == CPUFREQ_MAX) 444 if (frequency == cpu_frequency)
445 {
446 /* avoid redundant activity */
447 }
448 else if(frequency == CPUFREQ_MAX)
422 { 449 {
423#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE 450#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
424 /* Increasing frequency so boost voltage before change */ 451 /* Increasing frequency so boost voltage before change */
@@ -464,7 +491,11 @@ void set_cpu_frequency(long frequency)
464#else /* as3525v2 */ 491#else /* as3525v2 */
465void set_cpu_frequency(long frequency) 492void set_cpu_frequency(long frequency)
466{ 493{
467 if(frequency == CPUFREQ_MAX) 494 if (frequency == cpu_frequency)
495 {
496 /* avoid redundant activity */
497 }
498 else if(frequency == CPUFREQ_MAX)
468 { 499 {
469#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE 500#ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
470 /* Set CVDD1 power supply */ 501 /* Set CVDD1 power supply */
diff --git a/firmware/target/arm/as3525/system-target.h b/firmware/target/arm/as3525/system-target.h
index db5bb892ef..4fbbb46d5d 100644
--- a/firmware/target/arm/as3525/system-target.h
+++ b/firmware/target/arm/as3525/system-target.h
@@ -21,12 +21,17 @@
21#ifndef SYSTEM_TARGET_H 21#ifndef SYSTEM_TARGET_H
22#define SYSTEM_TARGET_H 22#define SYSTEM_TARGET_H
23 23
24/* we need some system things initialized after the kernel init */
25#define KDEV_INIT
26
24#include "system-arm.h" 27#include "system-arm.h"
25#include "mmu-arm.h" 28#include "mmu-arm.h"
26#include "panic.h" 29#include "panic.h"
27 30
28#include "clock-target.h" /* CPUFREQ_* are defined here */ 31#include "clock-target.h" /* CPUFREQ_* are defined here */
29 32
33void kernel_device_init(void);
34
30#define STORAGE_WANTS_ALIGN 35#define STORAGE_WANTS_ALIGN
31 36
32/* We can use a interrupt-based mechanism on the fuzev2 */ 37/* We can use a interrupt-based mechanism on the fuzev2 */
@@ -68,4 +73,20 @@ static inline void mdelay(unsigned msecs)
68void usb_insert_int(void); 73void usb_insert_int(void);
69void usb_remove_int(void); 74void usb_remove_int(void);
70 75
76#ifdef HAVE_ADJUSTABLE_CPU_FREQ
77#define CPU_BOOST_LOCK_DEFINED
78
79static inline bool cpu_boost_lock(void)
80{
81 bool set_cpu_frequency__lock(void);
82 return set_cpu_frequency__lock();
83}
84
85static inline void cpu_boost_unlock(void)
86{
87 void set_cpu_frequency__unlock(void);
88 set_cpu_frequency__unlock();
89}
90#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
91
71#endif /* SYSTEM_TARGET_H */ 92#endif /* SYSTEM_TARGET_H */
diff --git a/firmware/target/arm/pp/system-pp5002.c b/firmware/target/arm/pp/system-pp5002.c
index 3186d3739a..388f962fce 100644
--- a/firmware/target/arm/pp/system-pp5002.c
+++ b/firmware/target/arm/pp/system-pp5002.c
@@ -24,6 +24,11 @@
24#include "adc-target.h" 24#include "adc-target.h"
25#include "button-target.h" 25#include "button-target.h"
26 26
27#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1)
28#include "corelock.h"
29static struct corelock cpufreq_cl SHAREDBSS_ATTR;
30#endif
31
27extern void TIMER1(void); 32extern void TIMER1(void);
28extern void TIMER2(void); 33extern void TIMER2(void);
29 34
@@ -122,6 +127,18 @@ static void ipod_init_cache(void)
122} 127}
123 128
124#ifdef HAVE_ADJUSTABLE_CPU_FREQ 129#ifdef HAVE_ADJUSTABLE_CPU_FREQ
130#if NUM_CORES > 1
131void set_cpu_frequency__lock(void)
132{
133 corelock_lock(&cpufreq_cl);
134}
135
136void set_cpu_frequency__unlock(void)
137{
138 corelock_unlock(&cpufreq_cl);
139}
140#endif /* NUM_CORES > 1 */
141
125void set_cpu_frequency(long frequency) 142void set_cpu_frequency(long frequency)
126#else 143#else
127static void pp_set_cpu_frequency(long frequency) 144static void pp_set_cpu_frequency(long frequency)
@@ -193,7 +210,7 @@ void system_init(void)
193 210
194#ifdef HAVE_ADJUSTABLE_CPU_FREQ 211#ifdef HAVE_ADJUSTABLE_CPU_FREQ
195#if NUM_CORES > 1 212#if NUM_CORES > 1
196 cpu_boost_init(); 213 corelock_init(&cpufreq_cl);
197#endif 214#endif
198#else 215#else
199 pp_set_cpu_frequency(CPUFREQ_MAX); 216 pp_set_cpu_frequency(CPUFREQ_MAX);
diff --git a/firmware/target/arm/pp/system-pp502x.c b/firmware/target/arm/pp/system-pp502x.c
index 99b536e132..102cfd8fea 100644
--- a/firmware/target/arm/pp/system-pp502x.c
+++ b/firmware/target/arm/pp/system-pp502x.c
@@ -308,16 +308,24 @@ void scale_suspend_core(bool suspend)
308} 308}
309 309
310#ifdef HAVE_ADJUSTABLE_CPU_FREQ 310#ifdef HAVE_ADJUSTABLE_CPU_FREQ
311#if NUM_CORES > 1
312void set_cpu_frequency__lock(void)
313{
314 corelock_lock(&cpufreq_cl);
315}
316
317void set_cpu_frequency__unlock(void)
318{
319 corelock_unlock(&cpufreq_cl);
320}
321#endif /* NUM_CORES > 1 */
322
311void set_cpu_frequency(long frequency) ICODE_ATTR; 323void set_cpu_frequency(long frequency) ICODE_ATTR;
312void set_cpu_frequency(long frequency) 324void set_cpu_frequency(long frequency)
313#else 325#else
314static void pp_set_cpu_frequency(long frequency) 326static void pp_set_cpu_frequency(long frequency)
315#endif 327#endif
316{ 328{
317#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1)
318 corelock_lock(&cpufreq_cl);
319#endif
320
321 switch (frequency) 329 switch (frequency)
322 { 330 {
323 /* Note1: The PP5022 PLL must be run at >= 96MHz 331 /* Note1: The PP5022 PLL must be run at >= 96MHz
@@ -424,10 +432,6 @@ static void pp_set_cpu_frequency(long frequency)
424 DEV_INIT2 &= ~INIT_PLL; /* disable PLL power */ 432 DEV_INIT2 &= ~INIT_PLL; /* disable PLL power */
425 break; 433 break;
426 } 434 }
427
428#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1)
429 corelock_unlock(&cpufreq_cl);
430#endif
431} 435}
432#endif /* !BOOTLOADER || (SANSA_E200 || SANSA_C200 || PHILIPS_SA9200) */ 436#endif /* !BOOTLOADER || (SANSA_E200 || SANSA_C200 || PHILIPS_SA9200) */
433 437
@@ -544,7 +548,6 @@ void system_init(void)
544#ifdef HAVE_ADJUSTABLE_CPU_FREQ 548#ifdef HAVE_ADJUSTABLE_CPU_FREQ
545#if NUM_CORES > 1 549#if NUM_CORES > 1
546 corelock_init(&cpufreq_cl); 550 corelock_init(&cpufreq_cl);
547 cpu_boost_init();
548#endif 551#endif
549#else 552#else
550 pp_set_cpu_frequency(CPUFREQ_MAX); 553 pp_set_cpu_frequency(CPUFREQ_MAX);
diff --git a/firmware/target/arm/pp/system-target.h b/firmware/target/arm/pp/system-target.h
index d372b65502..1e947195bd 100644
--- a/firmware/target/arm/pp/system-target.h
+++ b/firmware/target/arm/pp/system-target.h
@@ -199,4 +199,21 @@ void system_prepare_fw_start(void);
199 199
200#endif /* BOOTLOADER */ 200#endif /* BOOTLOADER */
201 201
202#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1)
203#define CPU_BOOST_LOCK_DEFINED
204
205static inline bool cpu_boost_lock(void)
206{
207 void set_cpu_frequency__lock(void);
208 set_cpu_frequency__lock();
209 return true;
210}
211
212static inline void cpu_boost_unlock(void)
213{
214 void set_cpu_frequency__unlock(void);
215 set_cpu_frequency__unlock();
216}
217#endif /* HAVE_ADJUSTABLE_CPU_FREQ && NUM_CORES > 1 */
218
202#endif /* SYSTEM_TARGET_H */ 219#endif /* SYSTEM_TARGET_H */