video: mbp_nvidia_bl: Add support for MacBook 5, MacBook Air 2, and MacBook Pro 5
Subsystems (2)
PATCH 1/2 video: mbp_nvidia_bl: Add support for MacBook 5, MacBook Air 2, and MacBook Pro 5
This patch adds support for the new Apple models incorporating an Nvidia chipset. Apple still uses the same protocol as on older models, but the registers moved to a different address.
The initial code has been contributed by Hu Gang <[email protected]>.
Changes:
* new structure to be passed to the DMI_MATCH function
* separated implementation for Intel/Nvidia chipset models
* added new entries to the device table (moved down)
* used driver_data structure to request resources/access ops where necessary
Known to work on:
* MacBook Pro 3
* MacBook Pro 4
* MacBook Pro 5
Known to work with limitations on:
* MacBook 5 / MacBook Air 2:
Changing brightness within X doesn't work, if using Nvidia's proprietary graphics driver. No fix known yet. Changing brightness on a text console or using the open-source driver does work.
Known Bugs:
* MacBook Pro 5:
Initial brightness after bootup is the last recently used brightness (in Mac OSX), while the firmware reports maximum. Impossible to fix.
--- drivers/video/backlight/mbp_nvidia_bl.c | 171 ++++++++++++++++++++++++------- 1 files changed, 132 insertions(+), 39 deletions(-)
drivers/video/backlight/mbp_nvidia_bl.c +132 -39
@@ -25,63 +25,163 @@#include <linux/dmi.h> #include <linux/io.h> -static struct dmi_system_id __initdata mbp_device_table[] = { - { - .ident ="3,1" , - .matches = { -DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), -DMI_MATCH (DMI_PRODUCT_NAME ,"MacBookPro3,1" ), - }, - }, - { - .ident ="3,2" , - .matches = { -DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), -DMI_MATCH (DMI_PRODUCT_NAME ,"MacBookPro3,2" ), - }, - }, - { - .ident ="4,1" , - .matches = { -DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), -DMI_MATCH (DMI_PRODUCT_NAME ,"MacBookPro4,1" ), - }, - }, - { } +/* Structure to be passed to the DMI_MATCH function. */ +struct dmi_match_data { +/* I/O resource to allocate. */ +struct resource iores; +/* Backlight operations structure. */ +struct backlight_ops backlight_ops; }; -static int mbp_send_intensity (struct backlight_device *bd) +/* +* Implementation for MacBooks with Intel chipset. +*/ +static int intel_chipset_send_intensity (struct backlight_device *bd) {int intensity = bd->props.brightness;outb (0x04 | (intensity <<4 ),0xb3 );outb (0xbf ,0xb2 ); -return 0 ; } -static int mbp_get_intensity (struct backlight_device *bd) +static int intel_chipset_get_intensity (struct backlight_device *bd) {outb (0x03 ,0xb3 );outb (0xbf ,0xb2 );return inb (0xb3 ) >>4 ; } -static struct backlight_ops mbp_ops = { - .get_brightness = mbp_get_intensity, - .update_status = mbp_send_intensity, +static const struct dmi_match_data intel_chipset_data = { + .iores = { + .start =0xb2 , + .end =0xb3 , + .name ="mbp_nvidia_bl" , + .flags =IORESOURCE_IO + }, + .backlight_ops = { + .get_brightness = intel_chipset_get_intensity, + .update_status = intel_chipset_send_intensity, + } }; +/* +* Implementation for MacBooks with Nvidia chipset. +*/ +static int nvidia_chipset_send_intensity (struct backlight_device *bd) +{ +int intensity = bd->props.brightness; + +outb (0x04 | (intensity <<4 ),0x52f ); +outb (0xbf ,0x52e ); +return 0 ; +} + +static int nvidia_chipset_get_intensity (struct backlight_device *bd) +{ +outb (0x03 ,0x52f ); +outb (0xbf ,0x52e ); +return inb (0x52f ) >>4 ; +} + +static const struct dmi_match_data nvidia_chipset_data = { + .iores = { + .start =0x52e , + .end =0x52f , + .name ="mbp_nvidia_bl" , + .flags =IORESOURCE_IO , + }, + .backlight_ops = { + .get_brightness = nvidia_chipset_get_intensity, + .update_status = nvidia_chipset_send_intensity + } +}; + +/* +* DMI matching. +*/ +static /* const */ struct dmi_match_data *driver_data; + +static int dmi_match (const struct dmi_system_id *id) +{ + driver_data = id->driver_data; + +printk (KERN_INFO "mbp_nvidia_bl: %s detected\n" , id->ident); +return 1 ; +} + +static const struct dmi_system_id __initdata mbp_device_table[] = { + { + .callback = dmi_match, + .ident ="MacBookPro 3,1" , + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), +DMI_MATCH (DMI_PRODUCT_NAME ,"MacBookPro3,1" ), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = dmi_match, + .ident ="MacBookPro 3,2" , + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), +DMI_MATCH (DMI_PRODUCT_NAME ,"MacBookPro3,2" ), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = dmi_match, + .ident ="MacBookPro 4,1" , + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), +DMI_MATCH (DMI_PRODUCT_NAME ,"MacBookPro4,1" ), + }, + .driver_data = (void *)&intel_chipset_data, + }, + { + .callback = dmi_match, + .ident ="MacBook 5,1" , + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), +DMI_MATCH (DMI_PRODUCT_NAME ,"MacBook5,1" ), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = dmi_match, + .ident ="MacBookAir 2,1" , + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), +DMI_MATCH (DMI_PRODUCT_NAME ,"MacBookAir2,1" ), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = dmi_match, + .ident ="MacBookPro 5,1" , + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Apple Inc." ), +DMI_MATCH (DMI_PRODUCT_NAME ,"MacBookPro5,1" ), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { } +}; + +/* +* Platform driver implementation. +*/ static int mbp_probe (struct platform_device *pdev) {struct backlight_device *bd; - bd =backlight_device_register ("mbp_backlight" ,NULL ,NULL , &mbp_ops); + bd =backlight_device_register ("mbp_backlight" ,NULL ,NULL , + &driver_data->backlight_ops);if (IS_ERR (bd))return PTR_ERR (bd); bd->props.max_brightness =15 ; - bd->props.brightness =mbp_get_intensity (bd); + bd->props.brightness = bd->ops->get_brightness (bd);backlight_update_status (bd);platform_set_drvdata (pdev, bd);
@@ -128,13 +228,6 @@ static struct platform_driver mbp_driver = { }, }; -static struct resource mbp_iores = { - .start =0xb2 , - .end =0xb3 , - .name ="mbp_nvidia_bl" , - .flags =IORESOURCE_IO -}; -static struct platform_device *mbp_device;static int __init mbp_init (void )
@@ -149,7 +242,7 @@ static int __init mbp_init(void)return ret; mbp_device =platform_device_register_simple ("mbp_nvidia_bl" ,-1 , - &mbp_iores,1 ); + &driver_data->iores,1 );if (!mbp_device) {platform_driver_unregister (&mbp_driver);return -ENOMEM ;
Signature · 1 line
1.5.6.3
Quoted 5 lines · Mario Schwalbe
Known Bugs:
* MacBook Pro 5:
Initial brightness after bootup is the last recently used brightness (in Mac OSX), while the firmware reports maximum. Impossible to fix.
In that case, why not read the firmware value and then set that explicitly on driver load? Having the driver be in sync with the hardware is better than avoiding a brightness change on boot.
drivers/video/backlight/mbp_nvidia_bl.c line 53
Quoted 6 lines
drivers/video/backlight/mbp_nvidia_bl.c +1
-0+static int intel_chipset_get_intensity (struct backlight_device *bd) {outb (0x03 ,0xb3 );outb (0xbf ,0xb2 );return inb (0xb3 ) >>4 ; }
Just to absolutely clarify, this is intel chipset as in motherboard chipset and not graphics chipset, right? A comment to make that clear would be good - it left me a little confused at first. Other than that, it looks good.
Signature · 1 line
Matthew Garrett | [email protected]
Hi,
Quoted 10 lines · Matthew Garrett
Quoted 5 lines · Mario Schwalbe
Known Bugs:
* MacBook Pro 5:
Initial brightness after bootup is the last recently used brightness (in Mac OSX), while the firmware reports maximum. Impossible to fix.In that case, why not read the firmware value and then set that explicitly on driver load? Having the driver be in sync with the hardware is better than avoiding a brightness change on boot.
that's already the case. the previous code worked like that and the patch doesn't change that behaviour. however, the problem is:
(1) the driver tries to read the current setting which is always maximum, even through the actual brightness might be lower.
(2) afterwards the driver re-sends this value to hardware effectively setting the (visible) brightness to maximum. now hardware and software are consistent. that's a brightness change on boot we cannot avoid.
not re-sending the read value on boot is no solution either because if the user later decides to adjust brightness incrementally (by means of functions keys) it would immediately jump to some value near maximum with his adjustment applied. then after the first change, the state would be consistent.
Quoted 11 lines
drivers/video/backlight/mbp_nvidia_bl.c line 53
Quoted 6 lines
drivers/video/backlight/mbp_nvidia_bl.c +1
-0+static int intel_chipset_get_intensity (struct backlight_device *bd) {outb (0x03 ,0xb3 );outb (0xbf ,0xb2 );return inb (0xb3 ) >>4 ; }Just to absolutely clarify, this is intel chipset as in motherboard chipset and not graphics chipset, right? A comment to make that clear would be good - it left me a little confused at first. Other than that, it looks good.
yes, *_chipset refers to the motherboard chipset vendor.
ciao,
Mario
Signature · 15 lines
Wo das Chaos auf die Ordnung trifft, gewinnt meist das Chaos,
weil es besser organisiert ist.
- Friedrich Nietzsche -
--
_____ ________
/ \ / ____/ Mario Schwalbe
/ \ / \ \____ \
/ Y \/ \ eMail: [email protected],
\____|__ /______ / [email protected]
\/ \/
key ID: 7DA9 DAFF
public key: https://www1.inf.tu-dresden.de/~ms790178/key.asc
key fingerprint: 2979 AA20 4A93 B527 90CC 45E5 4B28 511A 7DA9 DAFFQuoted 3 lines · Mario Schwalbe
This patch adds support for the new Apple models incorporating an Nvidia chipset. Apple still uses the same protocol as on older models, but the registers moved to a different address.
Can you tell me which tree this is against? I can't seem to apply it against .28-rc9, should I be using something newer?
johannes