0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <linux/acpi.h>
0025 #include "psb_drv.h"
0026 #include "psb_irq.h"
0027 #include "psb_intel_reg.h"
0028
0029 #define PCI_ASLE 0xe4
0030 #define PCI_ASLS 0xfc
0031
0032 #define OPREGION_HEADER_OFFSET 0
0033 #define OPREGION_ACPI_OFFSET 0x100
0034 #define ACPI_CLID 0x01ac
0035 #define ACPI_CDCK 0x01b0
0036 #define OPREGION_SWSCI_OFFSET 0x200
0037 #define OPREGION_ASLE_OFFSET 0x300
0038 #define OPREGION_VBT_OFFSET 0x400
0039
0040 #define OPREGION_SIGNATURE "IntelGraphicsMem"
0041 #define MBOX_ACPI (1<<0)
0042 #define MBOX_SWSCI (1<<1)
0043 #define MBOX_ASLE (1<<2)
0044
0045 struct opregion_header {
0046 u8 signature[16];
0047 u32 size;
0048 u32 opregion_ver;
0049 u8 bios_ver[32];
0050 u8 vbios_ver[16];
0051 u8 driver_ver[16];
0052 u32 mboxes;
0053 u8 reserved[164];
0054 } __packed;
0055
0056
0057 struct opregion_acpi {
0058 u32 drdy;
0059 u32 csts;
0060 u32 cevt;
0061 u8 rsvd1[20];
0062 u32 didl[8];
0063 u32 cpdl[8];
0064 u32 cadl[8];
0065 u32 nadl[8];
0066 u32 aslp;
0067 u32 tidx;
0068 u32 chpd;
0069 u32 clid;
0070 u32 cdck;
0071 u32 sxsw;
0072 u32 evts;
0073 u32 cnot;
0074 u32 nrdy;
0075 u8 rsvd2[60];
0076 } __packed;
0077
0078
0079 struct opregion_swsci {
0080
0081 } __packed;
0082
0083
0084 struct opregion_asle {
0085 u32 ardy;
0086 u32 aslc;
0087 u32 tche;
0088 u32 alsi;
0089 u32 bclp;
0090 u32 pfit;
0091 u32 cblv;
0092 u16 bclm[20];
0093 u32 cpfm;
0094 u32 epfm;
0095 u8 plut[74];
0096 u32 pfmb;
0097 u8 rsvd[102];
0098 } __packed;
0099
0100
0101 #define ASLE_SET_ALS_ILLUM (1 << 0)
0102 #define ASLE_SET_BACKLIGHT (1 << 1)
0103 #define ASLE_SET_PFIT (1 << 2)
0104 #define ASLE_SET_PWM_FREQ (1 << 3)
0105 #define ASLE_REQ_MSK 0xf
0106
0107
0108 #define ASLE_ALS_ILLUM_FAILED (1<<10)
0109 #define ASLE_BACKLIGHT_FAILED (1<<12)
0110 #define ASLE_PFIT_FAILED (1<<14)
0111 #define ASLE_PWM_FREQ_FAILED (1<<16)
0112
0113
0114 #define ASLE_BCLP_VALID (1<<31)
0115 #define ASLE_BCLP_MSK (~(1<<31))
0116
0117
0118 #define ASLE_PFIT_VALID (1<<31)
0119 #define ASLE_PFIT_CENTER (1<<0)
0120 #define ASLE_PFIT_STRETCH_TEXT (1<<1)
0121 #define ASLE_PFIT_STRETCH_GFX (1<<2)
0122
0123
0124 #define ASLE_ALS_ILLUM_FAILED (1<<10)
0125 #define ASLE_BACKLIGHT_FAILED (1<<12)
0126 #define ASLE_PFIT_FAILED (1<<14)
0127 #define ASLE_PWM_FREQ_FAILED (1<<16)
0128
0129
0130 #define ASLE_BCLP_VALID (1<<31)
0131 #define ASLE_BCLP_MSK (~(1<<31))
0132
0133
0134 #define ASLE_PFIT_VALID (1<<31)
0135 #define ASLE_PFIT_CENTER (1<<0)
0136 #define ASLE_PFIT_STRETCH_TEXT (1<<1)
0137 #define ASLE_PFIT_STRETCH_GFX (1<<2)
0138
0139
0140 #define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
0141 #define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
0142 #define ASLE_PFMB_PWM_MASK (0x7ffffe00)
0143 #define ASLE_PFMB_PWM_VALID (1<<31)
0144
0145 #define ASLE_CBLV_VALID (1<<31)
0146
0147 static struct psb_intel_opregion *system_opregion;
0148
0149 static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
0150 {
0151 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0152 struct opregion_asle *asle = dev_priv->opregion.asle;
0153 struct backlight_device *bd = dev_priv->backlight_device;
0154
0155 DRM_DEBUG_DRIVER("asle set backlight %x\n", bclp);
0156
0157 if (!(bclp & ASLE_BCLP_VALID))
0158 return ASLE_BACKLIGHT_FAILED;
0159
0160 if (bd == NULL)
0161 return ASLE_BACKLIGHT_FAILED;
0162
0163 bclp &= ASLE_BCLP_MSK;
0164 if (bclp > 255)
0165 return ASLE_BACKLIGHT_FAILED;
0166
0167 gma_backlight_set(dev, bclp * bd->props.max_brightness / 255);
0168
0169 asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID;
0170
0171 return 0;
0172 }
0173
0174 static void psb_intel_opregion_asle_work(struct work_struct *work)
0175 {
0176 struct psb_intel_opregion *opregion =
0177 container_of(work, struct psb_intel_opregion, asle_work);
0178 struct drm_psb_private *dev_priv =
0179 container_of(opregion, struct drm_psb_private, opregion);
0180 struct opregion_asle *asle = opregion->asle;
0181 u32 asle_stat = 0;
0182 u32 asle_req;
0183
0184 if (!asle)
0185 return;
0186
0187 asle_req = asle->aslc & ASLE_REQ_MSK;
0188 if (!asle_req) {
0189 DRM_DEBUG_DRIVER("non asle set request??\n");
0190 return;
0191 }
0192
0193 if (asle_req & ASLE_SET_BACKLIGHT)
0194 asle_stat |= asle_set_backlight(&dev_priv->dev, asle->bclp);
0195
0196 asle->aslc = asle_stat;
0197
0198 }
0199
0200 void psb_intel_opregion_asle_intr(struct drm_device *dev)
0201 {
0202 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0203
0204 if (dev_priv->opregion.asle)
0205 schedule_work(&dev_priv->opregion.asle_work);
0206 }
0207
0208 #define ASLE_ALS_EN (1<<0)
0209 #define ASLE_BLC_EN (1<<1)
0210 #define ASLE_PFIT_EN (1<<2)
0211 #define ASLE_PFMB_EN (1<<3)
0212
0213 void psb_intel_opregion_enable_asle(struct drm_device *dev)
0214 {
0215 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0216 struct opregion_asle *asle = dev_priv->opregion.asle;
0217
0218 if (asle && system_opregion ) {
0219
0220
0221 gma_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
0222 gma_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
0223
0224 asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN
0225 | ASLE_PFMB_EN;
0226 asle->ardy = 1;
0227 }
0228 }
0229
0230 #define ACPI_EV_DISPLAY_SWITCH (1<<0)
0231 #define ACPI_EV_LID (1<<1)
0232 #define ACPI_EV_DOCK (1<<2)
0233
0234
0235 static int psb_intel_opregion_video_event(struct notifier_block *nb,
0236 unsigned long val, void *data)
0237 {
0238
0239
0240
0241
0242
0243
0244
0245 struct opregion_acpi *acpi;
0246
0247 if (!system_opregion)
0248 return NOTIFY_DONE;
0249
0250 acpi = system_opregion->acpi;
0251 acpi->csts = 0;
0252
0253 return NOTIFY_OK;
0254 }
0255
0256 static struct notifier_block psb_intel_opregion_notifier = {
0257 .notifier_call = psb_intel_opregion_video_event,
0258 };
0259
0260 void psb_intel_opregion_init(struct drm_device *dev)
0261 {
0262 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0263 struct psb_intel_opregion *opregion = &dev_priv->opregion;
0264
0265 if (!opregion->header)
0266 return;
0267
0268 if (opregion->acpi) {
0269
0270
0271
0272 opregion->acpi->csts = 0;
0273 opregion->acpi->drdy = 1;
0274
0275 system_opregion = opregion;
0276 register_acpi_notifier(&psb_intel_opregion_notifier);
0277 }
0278 }
0279
0280 void psb_intel_opregion_fini(struct drm_device *dev)
0281 {
0282 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0283 struct psb_intel_opregion *opregion = &dev_priv->opregion;
0284
0285 if (!opregion->header)
0286 return;
0287
0288 if (opregion->acpi) {
0289 opregion->acpi->drdy = 0;
0290
0291 system_opregion = NULL;
0292 unregister_acpi_notifier(&psb_intel_opregion_notifier);
0293 }
0294
0295 cancel_work_sync(&opregion->asle_work);
0296
0297
0298 iounmap(opregion->header);
0299 opregion->header = NULL;
0300 opregion->acpi = NULL;
0301 opregion->swsci = NULL;
0302 opregion->asle = NULL;
0303 opregion->vbt = NULL;
0304 }
0305
0306 int psb_intel_opregion_setup(struct drm_device *dev)
0307 {
0308 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0309 struct pci_dev *pdev = to_pci_dev(dev->dev);
0310 struct psb_intel_opregion *opregion = &dev_priv->opregion;
0311 u32 opregion_phy, mboxes;
0312 void __iomem *base;
0313 int err = 0;
0314
0315 pci_read_config_dword(pdev, PCI_ASLS, &opregion_phy);
0316 if (opregion_phy == 0) {
0317 DRM_DEBUG_DRIVER("ACPI Opregion not supported\n");
0318 return -ENOTSUPP;
0319 }
0320
0321 INIT_WORK(&opregion->asle_work, psb_intel_opregion_asle_work);
0322
0323 DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy);
0324 base = acpi_os_ioremap(opregion_phy, 8*1024);
0325 if (!base)
0326 return -ENOMEM;
0327
0328 if (memcmp(base, OPREGION_SIGNATURE, 16)) {
0329 DRM_DEBUG_DRIVER("opregion signature mismatch\n");
0330 err = -EINVAL;
0331 goto err_out;
0332 }
0333
0334 opregion->header = base;
0335 opregion->vbt = base + OPREGION_VBT_OFFSET;
0336
0337 opregion->lid_state = base + ACPI_CLID;
0338
0339 mboxes = opregion->header->mboxes;
0340 if (mboxes & MBOX_ACPI) {
0341 DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
0342 opregion->acpi = base + OPREGION_ACPI_OFFSET;
0343 }
0344
0345 if (mboxes & MBOX_ASLE) {
0346 DRM_DEBUG_DRIVER("ASLE supported\n");
0347 opregion->asle = base + OPREGION_ASLE_OFFSET;
0348 }
0349
0350 return 0;
0351
0352 err_out:
0353 iounmap(base);
0354 return err;
0355 }
0356