Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Backlight code for ATI Radeon based graphic cards
0004  *
0005  * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
0006  * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
0007  * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
0008  */
0009 
0010 #include "radeonfb.h"
0011 #include <linux/backlight.h>
0012 #include <linux/slab.h>
0013 
0014 #ifdef CONFIG_PMAC_BACKLIGHT
0015 #include <asm/backlight.h>
0016 #endif
0017 
0018 #define MAX_RADEON_LEVEL 0xFF
0019 
0020 struct radeon_bl_privdata {
0021     struct radeonfb_info *rinfo;
0022     uint8_t negative;
0023 };
0024 
0025 static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
0026         int level)
0027 {
0028     int rlevel;
0029 
0030     /* Get and convert the value */
0031     /* No locking of bl_curve since we read a single value */
0032     rlevel = pdata->rinfo->info->bl_curve[level] *
0033          FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
0034 
0035     if (rlevel < 0)
0036         rlevel = 0;
0037     else if (rlevel > MAX_RADEON_LEVEL)
0038         rlevel = MAX_RADEON_LEVEL;
0039 
0040     if (pdata->negative)
0041         rlevel = MAX_RADEON_LEVEL - rlevel;
0042 
0043     return rlevel;
0044 }
0045 
0046 static int radeon_bl_update_status(struct backlight_device *bd)
0047 {
0048     struct radeon_bl_privdata *pdata = bl_get_data(bd);
0049     struct radeonfb_info *rinfo = pdata->rinfo;
0050     u32 lvds_gen_cntl, tmpPixclksCntl;
0051     int level;
0052 
0053     if (rinfo->mon1_type != MT_LCD)
0054         return 0;
0055 
0056     /* We turn off the LCD completely instead of just dimming the
0057      * backlight. This provides some greater power saving and the display
0058      * is useless without backlight anyway.
0059      */
0060         if (bd->props.power != FB_BLANK_UNBLANK ||
0061         bd->props.fb_blank != FB_BLANK_UNBLANK)
0062         level = 0;
0063     else
0064         level = bd->props.brightness;
0065 
0066     del_timer_sync(&rinfo->lvds_timer);
0067     radeon_engine_idle();
0068 
0069     lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
0070     if (level > 0) {
0071         lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
0072         if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
0073             lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
0074             lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
0075             OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
0076             lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
0077             lvds_gen_cntl |=
0078                 (radeon_bl_get_level_brightness(pdata, level) <<
0079                  LVDS_BL_MOD_LEVEL_SHIFT);
0080             lvds_gen_cntl |= LVDS_ON;
0081             lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
0082             rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
0083             mod_timer(&rinfo->lvds_timer,
0084                   jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
0085         } else {
0086             lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
0087             lvds_gen_cntl |=
0088                 (radeon_bl_get_level_brightness(pdata, level) <<
0089                  LVDS_BL_MOD_LEVEL_SHIFT);
0090             OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
0091         }
0092         rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
0093         rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
0094             & LVDS_STATE_MASK;
0095     } else {
0096         /* Asic bug, when turning off LVDS_ON, we have to make sure
0097            RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
0098         */
0099         tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
0100         if (rinfo->is_mobility || rinfo->is_IGP)
0101             OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
0102         lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
0103         lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
0104                   LVDS_BL_MOD_LEVEL_SHIFT);
0105         lvds_gen_cntl |= LVDS_DISPLAY_DIS;
0106         OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
0107         udelay(100);
0108         lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
0109         OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
0110         lvds_gen_cntl &= ~(LVDS_DIGON);
0111         rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
0112         mod_timer(&rinfo->lvds_timer,
0113               jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
0114         if (rinfo->is_mobility || rinfo->is_IGP)
0115             OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
0116     }
0117     rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
0118     rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
0119 
0120     return 0;
0121 }
0122 
0123 static const struct backlight_ops radeon_bl_data = {
0124     .update_status  = radeon_bl_update_status,
0125 };
0126 
0127 void radeonfb_bl_init(struct radeonfb_info *rinfo)
0128 {
0129     struct backlight_properties props;
0130     struct backlight_device *bd;
0131     struct radeon_bl_privdata *pdata;
0132     char name[12];
0133 
0134     if (rinfo->mon1_type != MT_LCD)
0135         return;
0136 
0137 #ifdef CONFIG_PMAC_BACKLIGHT
0138     if (!pmac_has_backlight_type("ati") &&
0139         !pmac_has_backlight_type("mnca"))
0140         return;
0141 #endif
0142 
0143     pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
0144     if (!pdata) {
0145         printk("radeonfb: Memory allocation failed\n");
0146         goto error;
0147     }
0148 
0149     snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
0150 
0151     memset(&props, 0, sizeof(struct backlight_properties));
0152     props.type = BACKLIGHT_RAW;
0153     props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
0154     bd = backlight_device_register(name, rinfo->info->dev, pdata,
0155                        &radeon_bl_data, &props);
0156     if (IS_ERR(bd)) {
0157         rinfo->info->bl_dev = NULL;
0158         printk("radeonfb: Backlight registration failed\n");
0159         goto error;
0160     }
0161 
0162     pdata->rinfo = rinfo;
0163 
0164     /* Pardon me for that hack... maybe some day we can figure out in what
0165      * direction backlight should work on a given panel?
0166      */
0167     pdata->negative =
0168         (rinfo->family != CHIP_FAMILY_RV200 &&
0169          rinfo->family != CHIP_FAMILY_RV250 &&
0170          rinfo->family != CHIP_FAMILY_RV280 &&
0171          rinfo->family != CHIP_FAMILY_RV350);
0172 
0173 #ifdef CONFIG_PMAC_BACKLIGHT
0174     pdata->negative = pdata->negative ||
0175         of_machine_is_compatible("PowerBook4,3") ||
0176         of_machine_is_compatible("PowerBook6,3") ||
0177         of_machine_is_compatible("PowerBook6,5");
0178 #endif
0179 
0180     rinfo->info->bl_dev = bd;
0181     fb_bl_default_curve(rinfo->info, 0,
0182          63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
0183         217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
0184 
0185     bd->props.brightness = bd->props.max_brightness;
0186     bd->props.power = FB_BLANK_UNBLANK;
0187     backlight_update_status(bd);
0188 
0189     printk("radeonfb: Backlight initialized (%s)\n", name);
0190 
0191     return;
0192 
0193 error:
0194     kfree(pdata);
0195     return;
0196 }
0197 
0198 void radeonfb_bl_exit(struct radeonfb_info *rinfo)
0199 {
0200     struct backlight_device *bd = rinfo->info->bl_dev;
0201 
0202     if (bd) {
0203         struct radeon_bl_privdata *pdata;
0204 
0205         pdata = bl_get_data(bd);
0206         backlight_device_unregister(bd);
0207         kfree(pdata);
0208         rinfo->info->bl_dev = NULL;
0209 
0210         printk("radeonfb: Backlight unloaded\n");
0211     }
0212 }