diff options
author | Bob Moore <robert.moore@intel.com> | 2009-02-18 01:20:12 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-26 16:38:24 -0400 |
commit | c520abadbc56a2740021910d2c6412f826a10059 (patch) | |
tree | bb491ead1a13afcf759d42e29175c5391449661c /drivers/acpi/acpica/hwregs.c | |
parent | d3319d1717a250e92be66a487dc3e0429112c284 (diff) |
ACPICA: Fix writes to optional PM1B registers
On read, shift B register bits above the A bits. On write,
shift B bits down to zero before writing the B register. New:
acpi_hw_read_multiple, acpi_hw_write_multiple. These two functions now
transparently handle the (possible) split registers for PM1 Status,
Enable, and Control.
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/hwregs.c')
-rw-r--r-- | drivers/acpi/acpica/hwregs.c | 205 |
1 files changed, 140 insertions, 65 deletions
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 7ef0b8eadbc7..41f1173e02c2 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c | |||
@@ -51,6 +51,17 @@ | |||
51 | #define _COMPONENT ACPI_HARDWARE | 51 | #define _COMPONENT ACPI_HARDWARE |
52 | ACPI_MODULE_NAME("hwregs") | 52 | ACPI_MODULE_NAME("hwregs") |
53 | 53 | ||
54 | /* Local Prototypes */ | ||
55 | static acpi_status | ||
56 | acpi_hw_read_multiple(u32 *value, | ||
57 | struct acpi_generic_address *register_a, | ||
58 | struct acpi_generic_address *register_b); | ||
59 | |||
60 | static acpi_status | ||
61 | acpi_hw_write_multiple(u32 value, | ||
62 | struct acpi_generic_address *register_a, | ||
63 | struct acpi_generic_address *register_b); | ||
64 | |||
54 | /******************************************************************************* | 65 | /******************************************************************************* |
55 | * | 66 | * |
56 | * FUNCTION: acpi_hw_clear_acpi_status | 67 | * FUNCTION: acpi_hw_clear_acpi_status |
@@ -63,6 +74,7 @@ ACPI_MODULE_NAME("hwregs") | |||
63 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED | 74 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
64 | * | 75 | * |
65 | ******************************************************************************/ | 76 | ******************************************************************************/ |
77 | |||
66 | acpi_status acpi_hw_clear_acpi_status(void) | 78 | acpi_status acpi_hw_clear_acpi_status(void) |
67 | { | 79 | { |
68 | acpi_status status; | 80 | acpi_status status; |
@@ -143,64 +155,49 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) | |||
143 | acpi_status | 155 | acpi_status |
144 | acpi_hw_register_read(u32 register_id, u32 * return_value) | 156 | acpi_hw_register_read(u32 register_id, u32 * return_value) |
145 | { | 157 | { |
146 | u32 value1 = 0; | 158 | u32 value = 0; |
147 | u32 value2 = 0; | ||
148 | acpi_status status; | 159 | acpi_status status; |
149 | 160 | ||
150 | ACPI_FUNCTION_TRACE(hw_register_read); | 161 | ACPI_FUNCTION_TRACE(hw_register_read); |
151 | 162 | ||
152 | switch (register_id) { | 163 | switch (register_id) { |
153 | case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ | 164 | case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ |
154 | 165 | ||
155 | status = acpi_read(&value1, &acpi_gbl_xpm1a_status); | 166 | status = acpi_hw_read_multiple(&value, |
156 | if (ACPI_FAILURE(status)) { | 167 | &acpi_gbl_xpm1a_status, |
157 | goto exit; | 168 | &acpi_gbl_xpm1b_status); |
158 | } | ||
159 | |||
160 | /* PM1B is optional */ | ||
161 | |||
162 | status = acpi_read(&value2, &acpi_gbl_xpm1b_status); | ||
163 | value1 |= value2; | ||
164 | break; | 169 | break; |
165 | 170 | ||
166 | case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ | 171 | case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ |
167 | 172 | ||
168 | status = acpi_read(&value1, &acpi_gbl_xpm1a_enable); | 173 | status = acpi_hw_read_multiple(&value, |
169 | if (ACPI_FAILURE(status)) { | 174 | &acpi_gbl_xpm1a_enable, |
170 | goto exit; | 175 | &acpi_gbl_xpm1b_enable); |
171 | } | ||
172 | |||
173 | /* PM1B is optional */ | ||
174 | |||
175 | status = acpi_read(&value2, &acpi_gbl_xpm1b_enable); | ||
176 | value1 |= value2; | ||
177 | break; | 176 | break; |
178 | 177 | ||
179 | case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ | 178 | case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ |
180 | |||
181 | status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_control_block); | ||
182 | if (ACPI_FAILURE(status)) { | ||
183 | goto exit; | ||
184 | } | ||
185 | 179 | ||
186 | status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_control_block); | 180 | status = acpi_hw_read_multiple(&value, |
187 | value1 |= value2; | 181 | &acpi_gbl_FADT. |
182 | xpm1a_control_block, | ||
183 | &acpi_gbl_FADT. | ||
184 | xpm1b_control_block); | ||
188 | break; | 185 | break; |
189 | 186 | ||
190 | case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ | 187 | case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ |
191 | 188 | ||
192 | status = acpi_read(&value1, &acpi_gbl_FADT.xpm2_control_block); | 189 | status = acpi_read(&value, &acpi_gbl_FADT.xpm2_control_block); |
193 | break; | 190 | break; |
194 | 191 | ||
195 | case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ | 192 | case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ |
196 | 193 | ||
197 | status = acpi_read(&value1, &acpi_gbl_FADT.xpm_timer_block); | 194 | status = acpi_read(&value, &acpi_gbl_FADT.xpm_timer_block); |
198 | break; | 195 | break; |
199 | 196 | ||
200 | case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ | 197 | case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ |
201 | 198 | ||
202 | status = | 199 | status = |
203 | acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8); | 200 | acpi_os_read_port(acpi_gbl_FADT.smi_command, &value, 8); |
204 | break; | 201 | break; |
205 | 202 | ||
206 | default: | 203 | default: |
@@ -209,10 +206,8 @@ acpi_hw_register_read(u32 register_id, u32 * return_value) | |||
209 | break; | 206 | break; |
210 | } | 207 | } |
211 | 208 | ||
212 | exit: | ||
213 | |||
214 | if (ACPI_SUCCESS(status)) { | 209 | if (ACPI_SUCCESS(status)) { |
215 | *return_value = value1; | 210 | *return_value = value; |
216 | } | 211 | } |
217 | 212 | ||
218 | return_ACPI_STATUS(status); | 213 | return_ACPI_STATUS(status); |
@@ -252,12 +247,13 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value) | |||
252 | ACPI_FUNCTION_TRACE(hw_register_write); | 247 | ACPI_FUNCTION_TRACE(hw_register_write); |
253 | 248 | ||
254 | switch (register_id) { | 249 | switch (register_id) { |
255 | case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ | 250 | case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ |
256 | 251 | ||
257 | /* Perform a read first to preserve certain bits (per ACPI spec) */ | 252 | /* Perform a read first to preserve certain bits (per ACPI spec) */ |
258 | 253 | ||
259 | status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, | 254 | status = acpi_hw_read_multiple(&read_value, |
260 | &read_value); | 255 | &acpi_gbl_xpm1a_status, |
256 | &acpi_gbl_xpm1b_status); | ||
261 | if (ACPI_FAILURE(status)) { | 257 | if (ACPI_FAILURE(status)) { |
262 | goto exit; | 258 | goto exit; |
263 | } | 259 | } |
@@ -269,35 +265,29 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value) | |||
269 | 265 | ||
270 | /* Now we can write the data */ | 266 | /* Now we can write the data */ |
271 | 267 | ||
272 | status = acpi_write(value, &acpi_gbl_xpm1a_status); | 268 | status = acpi_hw_write_multiple(value, |
273 | if (ACPI_FAILURE(status)) { | 269 | &acpi_gbl_xpm1a_status, |
274 | goto exit; | 270 | &acpi_gbl_xpm1b_status); |
275 | } | ||
276 | |||
277 | /* PM1B is optional */ | ||
278 | |||
279 | status = acpi_write(value, &acpi_gbl_xpm1b_status); | ||
280 | break; | 271 | break; |
281 | 272 | ||
282 | case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ | 273 | case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access */ |
283 | 274 | ||
284 | status = acpi_write(value, &acpi_gbl_xpm1a_enable); | 275 | status = acpi_hw_write_multiple(value, |
285 | if (ACPI_FAILURE(status)) { | 276 | &acpi_gbl_xpm1a_enable, |
286 | goto exit; | 277 | &acpi_gbl_xpm1b_enable); |
287 | } | ||
288 | |||
289 | /* PM1B is optional */ | ||
290 | |||
291 | status = acpi_write(value, &acpi_gbl_xpm1b_enable); | ||
292 | break; | 278 | break; |
293 | 279 | ||
294 | case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ | 280 | case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ |
295 | 281 | ||
296 | /* | 282 | /* |
297 | * Perform a read first to preserve certain bits (per ACPI spec) | 283 | * Perform a read first to preserve certain bits (per ACPI spec) |
284 | * Note: This includes SCI_EN, we never want to change this bit | ||
298 | */ | 285 | */ |
299 | status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, | 286 | status = acpi_hw_read_multiple(&read_value, |
300 | &read_value); | 287 | &acpi_gbl_FADT. |
288 | xpm1a_control_block, | ||
289 | &acpi_gbl_FADT. | ||
290 | xpm1b_control_block); | ||
301 | if (ACPI_FAILURE(status)) { | 291 | if (ACPI_FAILURE(status)) { |
302 | goto exit; | 292 | goto exit; |
303 | } | 293 | } |
@@ -309,12 +299,11 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value) | |||
309 | 299 | ||
310 | /* Now we can write the data */ | 300 | /* Now we can write the data */ |
311 | 301 | ||
312 | status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block); | 302 | status = acpi_hw_write_multiple(value, |
313 | if (ACPI_FAILURE(status)) { | 303 | &acpi_gbl_FADT. |
314 | goto exit; | 304 | xpm1a_control_block, |
315 | } | 305 | &acpi_gbl_FADT. |
316 | 306 | xpm1b_control_block); | |
317 | status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block); | ||
318 | break; | 307 | break; |
319 | 308 | ||
320 | case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ | 309 | case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ |
@@ -346,6 +335,7 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value) | |||
346 | break; | 335 | break; |
347 | 336 | ||
348 | default: | 337 | default: |
338 | ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id)); | ||
349 | status = AE_BAD_PARAMETER; | 339 | status = AE_BAD_PARAMETER; |
350 | break; | 340 | break; |
351 | } | 341 | } |
@@ -353,3 +343,88 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value) | |||
353 | exit: | 343 | exit: |
354 | return_ACPI_STATUS(status); | 344 | return_ACPI_STATUS(status); |
355 | } | 345 | } |
346 | |||
347 | /****************************************************************************** | ||
348 | * | ||
349 | * FUNCTION: acpi_hw_read_multiple | ||
350 | * | ||
351 | * PARAMETERS: Value - Where the register value is returned | ||
352 | * register_a - First ACPI register (required) | ||
353 | * register_b - Second ACPI register (optional) | ||
354 | * | ||
355 | * RETURN: Status | ||
356 | * | ||
357 | * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) | ||
358 | * | ||
359 | ******************************************************************************/ | ||
360 | |||
361 | static acpi_status | ||
362 | acpi_hw_read_multiple(u32 *value, | ||
363 | struct acpi_generic_address *register_a, | ||
364 | struct acpi_generic_address *register_b) | ||
365 | { | ||
366 | u32 value_a = 0; | ||
367 | u32 value_b = 0; | ||
368 | acpi_status status; | ||
369 | |||
370 | /* The first register is always required */ | ||
371 | |||
372 | status = acpi_read(&value_a, register_a); | ||
373 | if (ACPI_FAILURE(status)) { | ||
374 | return (status); | ||
375 | } | ||
376 | |||
377 | /* Second register is optional */ | ||
378 | |||
379 | if (register_b->address) { | ||
380 | status = acpi_read(&value_b, register_b); | ||
381 | if (ACPI_FAILURE(status)) { | ||
382 | return (status); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | /* Shift the B bits above the A bits */ | ||
387 | |||
388 | *value = value_a | (value_b << register_a->bit_width); | ||
389 | return (AE_OK); | ||
390 | } | ||
391 | |||
392 | /****************************************************************************** | ||
393 | * | ||
394 | * FUNCTION: acpi_hw_write_multiple | ||
395 | * | ||
396 | * PARAMETERS: Value - The value to write | ||
397 | * register_a - First ACPI register (required) | ||
398 | * register_b - Second ACPI register (optional) | ||
399 | * | ||
400 | * RETURN: Status | ||
401 | * | ||
402 | * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) | ||
403 | * | ||
404 | ******************************************************************************/ | ||
405 | |||
406 | static acpi_status | ||
407 | acpi_hw_write_multiple(u32 value, | ||
408 | struct acpi_generic_address *register_a, | ||
409 | struct acpi_generic_address *register_b) | ||
410 | { | ||
411 | acpi_status status; | ||
412 | |||
413 | /* The first register is always required */ | ||
414 | |||
415 | status = acpi_write(value, register_a); | ||
416 | if (ACPI_FAILURE(status)) { | ||
417 | return (status); | ||
418 | } | ||
419 | |||
420 | /* Second register is optional */ | ||
421 | |||
422 | if (register_b->address) { | ||
423 | |||
424 | /* Normalize the B bits before write */ | ||
425 | |||
426 | status = acpi_write(value >> register_a->bit_width, register_b); | ||
427 | } | ||
428 | |||
429 | return (status); | ||
430 | } | ||