Hello,

I wrote this driver to control the backlight in my
MacBook Pro 2015 with Retina Display.

I had to refer to some of the code in the linux
apple-gmux.c driver to learn how to communicate
with the chip. This could cause an issue with the
license? That's why I haven't included any license
text in the file.

I also based this driver heavily on parts of asmc.c and abl.c

Built it today with current and it works correctly using
wsconsctl.

Does it stand any chance of getting commited?

Thanks,

Leonardo

Index: sys/arch/amd64/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.512
diff -u -p -u -p -r1.512 GENERIC
--- sys/arch/amd64/conf/GENERIC 8 Mar 2022 15:08:01 -0000 1.512
+++ sys/arch/amd64/conf/GENERIC 9 Sep 2022 16:30:21 -0000
@@ -82,6 +82,7 @@ tpm* at acpi?
 acpihve* at acpi?
 acpisurface* at acpi?
 acpihid* at acpi?
+gmux* at acpi?        # Apple MacBookPro Retina Backlight
 ipmi0 at acpi? disable
 ccpmic* at iic?
 tipmic* at iic?
Index: sys/dev/acpi/files.acpi
===================================================================
RCS file: /cvs/src/sys/dev/acpi/files.acpi,v
retrieving revision 1.65
diff -u -p -u -p -r1.65 files.acpi
--- sys/dev/acpi/files.acpi 31 Aug 2022 16:10:59 -0000 1.65
+++ sys/dev/acpi/files.acpi 9 Sep 2022 16:30:22 -0000
@@ -90,6 +90,11 @@ device abl
 attach abl at acpi
 file dev/acpi/abl.c abl

+# Apple MacBookPro Retina Display Backlight
+device  gmux
+attach  gmux at acpi
+file dev/acpi/gmux.c gmux
+
 # Apple System Management Controller (SMC)
 device asmc
 attach asmc at acpi
Index: sys/dev/acpi/gmux.c
===================================================================
RCS file: sys/dev/acpi/gmux.c
diff -N sys/dev/acpi/gmux.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/acpi/gmux.c 9 Sep 2022 16:30:22 -0000
@@ -0,0 +1,244 @@
+/*
+ * Driver to control backlight in MacBook Retina Display.
+ * Address numbers and inner workings heavily derived from
+ * apple-gmux Linux driver.
+ *
+ * */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/dsdt.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+
+#ifdef GMUX_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+#define GMUX_PORT_BRIGHTNESS 0x74
+#define GMUX_PORT_VALUE 0xc2
+#define GMUX_PORT_READ     0xd0
+#define GMUX_PORT_WRITE 0xd4
+
+#define GMUX_MIN_BRIGHTNESS 0
+#define GMUX_MAX_BRIGHTNESS 1023
+
+struct gmux_softc {
+ struct device sc_dev;
+
+ struct acpi_softc *sc_acpi;
+ struct aml_node *sc_devnode;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ uint16_t sc_brightness;
+};
+
+int gmux_match(struct device *, void *, void *);
+void gmux_attach(struct device *, struct device *, void *);
+void gmux_complete(struct gmux_softc *);
+void gmux_ready(struct gmux_softc *);
+bool gmux_confirm_retina_display(struct gmux_softc *);
+int gmux_get_brightness(struct gmux_softc *);
+int gmux_set_brightness(struct gmux_softc *,uint16_t);
+
+/* Hooks for wsconsole brightness control. */
+int gmux_get_param(struct wsdisplay_param *);
+int gmux_set_param(struct wsdisplay_param *);
+
+const struct cfattach gmux_ca = {
+ sizeof(struct gmux_softc), gmux_match, gmux_attach, NULL, NULL
+};
+
+struct cfdriver gmux_cd = {
+ NULL, "gmux", DV_DULL
+};
+
+const char *gmux_hids[] = {
+ "APP000B", NULL
+};
+
+int
+gmux_match(struct device *parent, void *match, void *aux)
+{
+ struct acpi_attach_args *aa = aux;
+ struct cfdata *cf = match;
+
+ return acpi_matchhids(aa, gmux_hids, cf->cf_driver->cd_name);
+
+}
+
+void
+gmux_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gmux_softc *sc = (struct gmux_softc *)self;
+ struct acpi_attach_args *aaa = aux;
+ struct aml_value res;
+ int64_t sta;
+
+ sc->sc_acpi = (struct acpi_softc *)parent;
+ sc->sc_devnode = aaa->aaa_node;
+
+ printf(": %s", sc->sc_devnode->name);
+
+        sta = acpi_getsta(sc->sc_acpi, sc->sc_devnode);
+ if ((sta & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
+     (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) {
+ printf(": not enabled\n");
+ return;
+ }
+
+ if (!(aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CID", 0, NULL, &res)))
+ printf(" (%s)", res.v_string);
+
+ if (strncmp(hw_prod, "MacBookPro11,5", 14)){
+ printf("\n");
+ return;
+ }
+
+ sc->sc_iot = aaa->aaa_iot;
+ if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0], 0,
+     &sc->sc_ioh)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ if (!gmux_confirm_retina_display(sc))
+ return;
+
+ /* Set initial brightness to maximum */
+ sc->sc_brightness = gmux_set_brightness(sc,GMUX_MAX_BRIGHTNESS);
+
+ /* Map wsconsole hook functions. */
+ ws_get_param = gmux_get_param;
+ ws_set_param = gmux_set_param;
+
+ printf("\n");
+}
+
+bool
+gmux_confirm_retina_display(struct gmux_softc *sc)
+{
+ uint16_t retina_value;
+
+ /* Values that confirm that gmux chip is for retina display*/
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,0xcc,0xaa);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,0xcd,0x55);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,0xce,0x00);
+
+ retina_value = bus_space_read_2(sc->sc_iot,sc->sc_ioh,0xcc) |
+ (bus_space_read_1(sc->sc_iot,sc->sc_ioh,0xcd) << 8);
+ if (retina_value == 0x55aa)
+ return true;
+ else
+ return false;
+}
+
+void
+gmux_complete(struct gmux_softc *sc)
+{
+ int counter = 50;
+ uint8_t complete;
+
+ complete = bus_space_read_1(sc->sc_iot,sc->sc_ioh,GMUX_PORT_WRITE);
+ while (counter && !(complete & 0x01)){
+ complete = bus_space_read_1(sc->sc_iot,sc->sc_ioh,
+ GMUX_PORT_WRITE);
+ delay(10);
+ counter--;
+ }
+
+ if (complete & 0x01)
+ bus_space_read_1(sc->sc_iot,sc->sc_ioh,GMUX_PORT_WRITE);
+
+}
+
+void
+gmux_ready(struct gmux_softc *sc)
+{
+ int counter = 50;
+ uint8_t ready;
+ ready = bus_space_read_1(sc->sc_iot,sc->sc_ioh,GMUX_PORT_WRITE);
+ while (counter && (ready & 0x01)){
+ bus_space_read_1(sc->sc_iot,sc->sc_ioh,GMUX_PORT_READ);
+ ready = bus_space_read_1(sc->sc_iot,sc->sc_ioh,
+ GMUX_PORT_WRITE);
+ delay(10);
+ counter--;
+ }
+}
+
+int
+gmux_get_brightness(struct gmux_softc *sc)
+{
+ gmux_ready(sc);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,GMUX_PORT_READ,
+ GMUX_PORT_BRIGHTNESS);
+ gmux_complete(sc);
+ return bus_space_read_4(sc->sc_iot,sc->sc_ioh,GMUX_PORT_VALUE);
+}
+
+int
+gmux_set_brightness(struct gmux_softc *sc, uint16_t brightness)
+{
+ bus_space_write_4(sc->sc_iot,sc->sc_ioh,GMUX_PORT_VALUE,brightness);
+
+ gmux_ready(sc);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,GMUX_PORT_WRITE,
+ GMUX_PORT_BRIGHTNESS);
+ gmux_complete(sc);
+ return brightness;
+}
+
+int
+gmux_get_param(struct wsdisplay_param *dp)
+{
+ struct gmux_softc *sc = gmux_cd.cd_devs[0];
+
+ if (sc == NULL)
+ return -1;
+
+ switch (dp->param) {
+ case WSDISPLAYIO_PARAM_BACKLIGHT:
+ DPRINTF(("gmux_get_param: sc->sc_brightness = %d\n",
+     sc->sc_brightness));
+ dp->min = GMUX_MIN_BRIGHTNESS;
+ dp->max = GMUX_MAX_BRIGHTNESS;
+ dp->curval = sc->sc_brightness;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+
+int gmux_set_param(struct wsdisplay_param *dp)
+{
+ struct gmux_softc *sc = gmux_cd.cd_devs[0];
+
+ if (sc == NULL)
+ return -1;
+
+ switch (dp->param) {
+ case WSDISPLAYIO_PARAM_BACKLIGHT:
+ DPRINTF(("gmux_set_param: curval = %d\n", dp->curval));
+ if (dp->curval < GMUX_MIN_BRIGHTNESS)
+ dp->curval = 0;
+ if (dp->curval > GMUX_MAX_BRIGHTNESS)
+ dp->curval = GMUX_MAX_BRIGHTNESS;
+ gmux_set_brightness(sc,dp->curval);
+ sc->sc_brightness = dp->curval;
+ return 0;
+ default:
+ return -1;
+ }
+}

Reply via email to