162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Backlight code for nVidia based graphic cards 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2004 Antonino Daplas <adaplas@pol.net> 662306a36Sopenharmony_ci * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/backlight.h> 1062306a36Sopenharmony_ci#include <linux/fb.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT 1462306a36Sopenharmony_ci#include <asm/backlight.h> 1562306a36Sopenharmony_ci#endif 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "nv_local.h" 1862306a36Sopenharmony_ci#include "nv_type.h" 1962306a36Sopenharmony_ci#include "nv_proto.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* We do not have any information about which values are allowed, thus 2262306a36Sopenharmony_ci * we used safe values. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci#define MIN_LEVEL 0x158 2562306a36Sopenharmony_ci#define MAX_LEVEL 0x534 2662306a36Sopenharmony_ci#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int nvidia_bl_get_level_brightness(struct nvidia_par *par, 2962306a36Sopenharmony_ci int level) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct fb_info *info = pci_get_drvdata(par->pci_dev); 3262306a36Sopenharmony_ci int nlevel; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci /* Get and convert the value */ 3562306a36Sopenharmony_ci /* No locking of bl_curve since we read a single value */ 3662306a36Sopenharmony_ci nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (nlevel < 0) 3962306a36Sopenharmony_ci nlevel = 0; 4062306a36Sopenharmony_ci else if (nlevel < MIN_LEVEL) 4162306a36Sopenharmony_ci nlevel = MIN_LEVEL; 4262306a36Sopenharmony_ci else if (nlevel > MAX_LEVEL) 4362306a36Sopenharmony_ci nlevel = MAX_LEVEL; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci return nlevel; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int nvidia_bl_update_status(struct backlight_device *bd) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct nvidia_par *par = bl_get_data(bd); 5162306a36Sopenharmony_ci u32 tmp_pcrt, tmp_pmc, fpcontrol; 5262306a36Sopenharmony_ci int level = backlight_get_brightness(bd); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (!par->FlatPanel) 5562306a36Sopenharmony_ci return 0; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF; 5862306a36Sopenharmony_ci tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC; 5962306a36Sopenharmony_ci fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (level > 0) { 6262306a36Sopenharmony_ci tmp_pcrt |= 0x1; 6362306a36Sopenharmony_ci tmp_pmc |= (1 << 31); /* backlight bit */ 6462306a36Sopenharmony_ci tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16; 6562306a36Sopenharmony_ci fpcontrol |= par->fpSyncs; 6662306a36Sopenharmony_ci } else 6762306a36Sopenharmony_ci fpcontrol |= 0x20000022; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt); 7062306a36Sopenharmony_ci NV_WR32(par->PMC, 0x10F0, tmp_pmc); 7162306a36Sopenharmony_ci NV_WR32(par->PRAMDAC, 0x848, fpcontrol); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic const struct backlight_ops nvidia_bl_ops = { 7762306a36Sopenharmony_ci .update_status = nvidia_bl_update_status, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid nvidia_bl_init(struct nvidia_par *par) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct backlight_properties props; 8362306a36Sopenharmony_ci struct fb_info *info = pci_get_drvdata(par->pci_dev); 8462306a36Sopenharmony_ci struct backlight_device *bd; 8562306a36Sopenharmony_ci char name[12]; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (!par->FlatPanel) 8862306a36Sopenharmony_ci return; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT 9162306a36Sopenharmony_ci if (!machine_is(powermac) || 9262306a36Sopenharmony_ci !pmac_has_backlight_type("mnca")) 9362306a36Sopenharmony_ci return; 9462306a36Sopenharmony_ci#endif 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci snprintf(name, sizeof(name), "nvidiabl%d", info->node); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci memset(&props, 0, sizeof(struct backlight_properties)); 9962306a36Sopenharmony_ci props.type = BACKLIGHT_RAW; 10062306a36Sopenharmony_ci props.max_brightness = FB_BACKLIGHT_LEVELS - 1; 10162306a36Sopenharmony_ci bd = backlight_device_register(name, info->device, par, &nvidia_bl_ops, 10262306a36Sopenharmony_ci &props); 10362306a36Sopenharmony_ci if (IS_ERR(bd)) { 10462306a36Sopenharmony_ci info->bl_dev = NULL; 10562306a36Sopenharmony_ci printk(KERN_WARNING "nvidia: Backlight registration failed\n"); 10662306a36Sopenharmony_ci goto error; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci info->bl_dev = bd; 11062306a36Sopenharmony_ci fb_bl_default_curve(info, 0, 11162306a36Sopenharmony_ci 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL, 11262306a36Sopenharmony_ci 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci bd->props.brightness = bd->props.max_brightness; 11562306a36Sopenharmony_ci bd->props.power = FB_BLANK_UNBLANK; 11662306a36Sopenharmony_ci backlight_update_status(bd); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci printk("nvidia: Backlight initialized (%s)\n", name); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cierror: 12162306a36Sopenharmony_ci return; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_civoid nvidia_bl_exit(struct nvidia_par *par) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct fb_info *info = pci_get_drvdata(par->pci_dev); 12762306a36Sopenharmony_ci struct backlight_device *bd = info->bl_dev; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci backlight_device_unregister(bd); 13062306a36Sopenharmony_ci printk("nvidia: Backlight unloaded\n"); 13162306a36Sopenharmony_ci} 132