Date: Sat, 02 Aug 2014 18:10:05 -0400 From: Anthony Jenkins <Anthony.B.Jenkins@att.net> To: freebsd-acpi@freebsd.org Subject: [PATCH] ACPI CMOS region support - submission? Message-ID: <53DD61BD.7050508@att.net>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Okay how do I get this bad boy into -CURRENT? Do I need a sponsor to do the commit? Get my own FreeBSD developer status?
I made a few minor changes since the last incarnation:
- Defined the CMOS address/data register addresses as macros
- Defined the (apparent) I/O delay as a macro
I also verified the ACPI CMOS region code only accesses up to register 63 (0x3F - in previous emails I mistakenly said 0x7F).
If/when this gets in, I'd like to add sysctl controls to e.g. allow ACPI access to the date/time registers (I currently return failure when attempting to write them via ACPI). I don't see anything in the spec (after re-reading it) that disallows ACPI from touching those.
Thanks,
Anthony Jenkins
[-- Attachment #2 --]
Index: sys/x86/isa/atrtc.c
===================================================================
--- sys/x86/isa/atrtc.c (revision 268728)
+++ sys/x86/isa/atrtc.c (working copy)
@@ -31,6 +31,7 @@
__FBSDID("$FreeBSD$");
#include "opt_isa.h"
+#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -53,12 +54,19 @@
#include <machine/intr_machdep.h>
#include "clock_if.h"
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+#include <dev/acpica/acpivar.h>
+
#define RTC_LOCK do { if (!kdb_active) mtx_lock_spin(&clock_lock); } while (0)
#define RTC_UNLOCK do { if (!kdb_active) mtx_unlock_spin(&clock_lock); } while (0)
+#define IO_DELAY() (void)inb(0x84)
+#define IO_RTC_ADDR (IO_RTC + 0)
+#define IO_RTC_DATA (IO_RTC + 1)
+
int atrtcclock_disable = 0;
-static int rtc_reg = -1;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static u_char rtc_statusb = RTCSB_24HR;
@@ -66,39 +74,50 @@
* RTC support routines
*/
-int
-rtcin(int reg)
+static void acpi_cmos_read(ACPI_PHYSICAL_ADDRESS address, UINT8 *buf, UINT32 buflen)
{
- u_char val;
+ UINT32 offset;
RTC_LOCK;
- if (rtc_reg != reg) {
- inb(0x84);
- outb(IO_RTC, reg);
- rtc_reg = reg;
- inb(0x84);
+ for (offset = 0U; offset < buflen; ++offset) {
+ IO_DELAY();
+ outb(IO_RTC_ADDR, ((address + offset) | 0x80) & 0xFF);
+ IO_DELAY();
+ buf[offset] = inb(IO_RTC_DATA);
}
- val = inb(IO_RTC + 1);
RTC_UNLOCK;
- return (val);
}
-void
-writertc(int reg, u_char val)
+static void acpi_cmos_write(ACPI_PHYSICAL_ADDRESS address, const UINT8 *buf, UINT32 buflen)
{
+ UINT32 offset;
RTC_LOCK;
- if (rtc_reg != reg) {
- inb(0x84);
- outb(IO_RTC, reg);
- rtc_reg = reg;
- inb(0x84);
+ for (offset = 0U; offset < buflen; ++offset) {
+ IO_DELAY();
+ outb(IO_RTC_ADDR, ((address + offset) | 0x80) & 0xFF);
+ IO_DELAY();
+ outb(IO_RTC_DATA, buf[offset]);
}
- outb(IO_RTC + 1, val);
- inb(0x84);
+ IO_DELAY();
RTC_UNLOCK;
}
+int
+rtcin(int reg)
+{
+ u_char val;
+
+ acpi_cmos_read(reg & 0xFF, &val, 1);
+ return (val);
+}
+
+void
+writertc(int reg, u_char val)
+{
+ acpi_cmos_write(reg & 0xFF, &val, 1);
+}
+
static __inline int
readrtc(int port)
{
@@ -144,7 +163,6 @@
{
/* Restore all of the RTC's "status" (actually, control) registers. */
- rtcin(RTC_STATUSA); /* dummy to get rtc_reg set */
writertc(RTC_STATUSB, RTCSB_24HR);
writertc(RTC_STATUSA, rtc_statusa);
writertc(RTC_STATUSB, rtc_statusb);
@@ -161,9 +179,52 @@
struct resource *intr_res;
void *intr_handler;
struct eventtimer et;
+ ACPI_HANDLE acpi_handle; /* Handle of the PNP0B00 node */
};
static int
+is_datetime_reg(ACPI_PHYSICAL_ADDRESS address)
+{
+ return address == 0x00 ||
+ address == 0x02 ||
+ address == 0x04 ||
+ address == 0x04 ||
+ (address >= 0x06 && address <= 0x09);
+}
+
+static ACPI_STATUS
+acpi_rtc_cmos_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address, UINT32 width,
+ UINT64 *value, void *context, void *region_context)
+{
+ struct atrtc_softc *sc;
+
+ sc = (struct atrtc_softc *)context;
+ if (!value || !sc)
+ return AE_BAD_PARAMETER;
+ if (width > 32 || (width & 0x07) || address >= 64U)
+ return AE_BAD_PARAMETER;
+ if (function == ACPI_WRITE &&
+ (is_datetime_reg(address) ||
+ (width > 8 && address <= 0x09)))
+ return AE_BAD_PARAMETER;
+
+ switch (function) {
+ case ACPI_READ:
+ acpi_cmos_read(address, (UINT8 *)value, width >> 3);
+ break;
+ case ACPI_WRITE:
+ acpi_cmos_write(address, (const UINT8 *)value, width >> 3);
+ break;
+ default:
+ return AE_BAD_PARAMETER;
+ }
+ printf("%s: %-5s%02u address=%04lx value=%08x\n",
+ __FUNCTION__, function == ACPI_READ ? "READ" : "WRITE",
+ width >> 3, address, *((UINT32 *)value));
+ return AE_OK;
+}
+
+static int
rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
{
@@ -245,10 +306,17 @@
int i;
sc = device_get_softc(dev);
+ sc->acpi_handle = acpi_get_handle(dev);
sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
IO_RTC, IO_RTC + 1, 2, RF_ACTIVE);
if (sc->port_res == NULL)
device_printf(dev, "Warning: Couldn't map I/O.\n");
+ if (ACPI_FAILURE(AcpiInstallAddressSpaceHandler(sc->acpi_handle,
+ ACPI_ADR_SPACE_CMOS, acpi_rtc_cmos_handler, NULL, sc)))
+ {
+ device_printf(dev, "Error registering ACPI CMOS address space handler.\n");
+ return 0;
+ }
atrtc_start();
clock_register(dev, 1000000);
bzero(&sc->et, sizeof(struct eventtimer));
@@ -286,6 +354,15 @@
return(0);
}
+static int atrtc_detach(device_t dev)
+{
+ struct atrtc_softc *sc;
+
+ sc = device_get_softc(dev);
+ AcpiRemoveAddressSpaceHandler(sc->acpi_handle, ACPI_ADR_SPACE_CMOS, acpi_rtc_cmos_handler);
+ return bus_generic_detach(dev);
+}
+
static int
atrtc_resume(device_t dev)
{
@@ -366,7 +443,7 @@
/* Device interface */
DEVMETHOD(device_probe, atrtc_probe),
DEVMETHOD(device_attach, atrtc_attach),
- DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_detach, atrtc_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
/* XXX stop statclock? */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?53DD61BD.7050508>
