* Re: [PATCH 14/19] video/vga: Add VGA_IS0_R
From: kernel test robot @ 2025-12-08 21:07 UTC (permalink / raw)
To: Ville Syrjala, intel-gfx
Cc: oe-kbuild-all, intel-xe, Helge Deller, linux-fbdev, dri-devel
In-Reply-To: <20251208182637.334-15-ville.syrjala@linux.intel.com>
Hi Ville,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-tip/drm-tip]
[cannot apply to drm-i915/for-linux-next drm-i915/for-linux-next-fixes linus/master v6.18 next-20251208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Ville-Syrjala/drm-i915-vga-Register-vgaarb-client-later/20251209-030730
base: https://gitlab.freedesktop.org/drm/tip.git drm-tip
patch link: https://lore.kernel.org/r/20251208182637.334-15-ville.syrjala%40linux.intel.com
patch subject: [PATCH 14/19] video/vga: Add VGA_IS0_R
config: microblaze-randconfig-r072-20251209 (https://download.01.org/0day-ci/archive/20251209/202512090434.DRy1Kvan-lkp@intel.com/config)
compiler: microblaze-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251209/202512090434.DRy1Kvan-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512090434.DRy1Kvan-lkp@intel.com/
All error/warnings (new ones prefixed by >>):
In file included from include/linux/vgaarb.h:15,
from drivers/video/aperture.c:12:
>> include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
In file included from drivers/video/aperture.c:14:
>> include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
drivers/video/aperture.c: In function 'devm_aperture_acquire_release':
>> drivers/video/aperture.c:153:21: error: dereferencing pointer to incomplete type 'struct aperture_range'
bool detached = !ap->dev;
^~
In file included from include/linux/bits.h:30,
from include/linux/ratelimit_types.h:5,
from include/linux/ratelimit.h:5,
from include/linux/dev_printk.h:16,
from include/linux/device.h:15,
from drivers/video/aperture.c:4:
drivers/video/aperture.c: In function 'devm_aperture_acquire':
>> include/linux/container_of.h:21:47: error: dereferencing pointer to incomplete type 'struct aperture_range'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~
include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert'
#define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
^~~~
include/linux/container_of.h:21:2: note: in expansion of macro 'static_assert'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~~~~~~~~~~~~
include/linux/container_of.h:21:16: note: in expansion of macro '__same_type'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~~~~~~~~~~
drivers/video/aperture.c:174:8: note: in expansion of macro 'container_of'
ap = container_of(pos, struct aperture_range, lh);
^~~~~~~~~~~~
include/linux/compiler_types.h:537:27: error: expression in static assertion is not an integer
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert'
#define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
^~~~
include/linux/container_of.h:21:2: note: in expansion of macro 'static_assert'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~~~~~~~~~~~~
include/linux/container_of.h:21:16: note: in expansion of macro '__same_type'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~~~~~~~~~~
drivers/video/aperture.c:174:8: note: in expansion of macro 'container_of'
ap = container_of(pos, struct aperture_range, lh);
^~~~~~~~~~~~
In file included from include/uapi/linux/posix_types.h:5,
from include/uapi/linux/types.h:14,
from include/linux/types.h:6,
from include/linux/aperture.h:6,
from drivers/video/aperture.c:3:
>> include/linux/stddef.h:16:32: error: invalid use of undefined type 'struct aperture_range'
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
^~~~~~~~~~~~~~~~~~
include/linux/container_of.h:24:21: note: in expansion of macro 'offsetof'
((type *)(__mptr - offsetof(type, member))); })
^~~~~~~~
drivers/video/aperture.c:174:8: note: in expansion of macro 'container_of'
ap = container_of(pos, struct aperture_range, lh);
^~~~~~~~~~~~
In file included from include/linux/bits.h:30,
from include/linux/ratelimit_types.h:5,
from include/linux/ratelimit.h:5,
from include/linux/dev_printk.h:16,
from include/linux/device.h:15,
from drivers/video/aperture.c:4:
drivers/video/aperture.c: In function 'aperture_detach_devices':
>> include/linux/container_of.h:21:47: error: dereferencing pointer to incomplete type 'struct aperture_range'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~
include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert'
#define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
^~~~
include/linux/container_of.h:21:2: note: in expansion of macro 'static_assert'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~~~~~~~~~~~~
include/linux/container_of.h:21:16: note: in expansion of macro '__same_type'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~~~~~~~~~~
drivers/video/aperture.c:255:31: note: in expansion of macro 'container_of'
struct aperture_range *ap = container_of(pos, struct aperture_range, lh);
^~~~~~~~~~~~
include/linux/compiler_types.h:537:27: error: expression in static assertion is not an integer
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert'
#define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
^~~~
include/linux/container_of.h:21:2: note: in expansion of macro 'static_assert'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~~~~~~~~~~~~
include/linux/container_of.h:21:16: note: in expansion of macro '__same_type'
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
^~~~~~~~~~~
drivers/video/aperture.c:255:31: note: in expansion of macro 'container_of'
struct aperture_range *ap = container_of(pos, struct aperture_range, lh);
^~~~~~~~~~~~
In file included from include/uapi/linux/posix_types.h:5,
from include/uapi/linux/types.h:14,
from include/linux/types.h:6,
from include/linux/aperture.h:6,
from drivers/video/aperture.c:3:
>> include/linux/stddef.h:16:32: error: invalid use of undefined type 'struct aperture_range'
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
^~~~~~~~~~~~~~~~~~
include/linux/container_of.h:24:21: note: in expansion of macro 'offsetof'
((type *)(__mptr - offsetof(type, member))); })
^~~~~~~~
drivers/video/aperture.c:255:31: note: in expansion of macro 'container_of'
struct aperture_range *ap = container_of(pos, struct aperture_range, lh);
^~~~~~~~~~~~
--
In file included from drivers/gpu/drm/mgag200/mgag200_drv.h:13,
from drivers/gpu/drm/mgag200/mgag200_bmc.c:10:
>> include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
In file included from include/linux/dma-buf.h:16,
from include/drm/drm_gem.h:38,
from drivers/gpu/drm/mgag200/mgag200_drv.h:18,
from drivers/gpu/drm/mgag200/mgag200_bmc.c:10:
>> include/linux/iosys-map.h:183:47: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline void iosys_map_set_vaddr(struct iosys_map *map, void *vaddr)
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_set_vaddr':
>> include/linux/iosys-map.h:185:5: error: dereferencing pointer to incomplete type 'struct iosys_map'
map->vaddr = vaddr;
^~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:196:53: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline void iosys_map_set_vaddr_iomem(struct iosys_map *map,
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_set_vaddr_iomem':
include/linux/iosys-map.h:199:5: error: dereferencing pointer to incomplete type 'struct iosys_map'
map->vaddr_iomem = vaddr_iomem;
^~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:214:52: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline bool iosys_map_is_equal(const struct iosys_map *lhs,
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_is_equal':
>> include/linux/iosys-map.h:217:9: error: dereferencing pointer to incomplete type 'const struct iosys_map'
if (lhs->is_iomem != rhs->is_iomem)
^~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:235:51: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline bool iosys_map_is_null(const struct iosys_map *map)
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_is_null':
include/linux/iosys-map.h:237:9: error: dereferencing pointer to incomplete type 'const struct iosys_map'
if (map->is_iomem)
^~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:252:50: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline bool iosys_map_is_set(const struct iosys_map *map)
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_is_set':
>> include/linux/iosys-map.h:254:28: error: passing argument 1 of 'iosys_map_is_null' from incompatible pointer type [-Werror=incompatible-pointer-types]
return !iosys_map_is_null(map);
^~~
include/linux/iosys-map.h:235:62: note: expected 'const struct iosys_map *' but argument is of type 'const struct iosys_map *'
static inline bool iosys_map_is_null(const struct iosys_map *map)
~~~~~~~~~~~~~~~~~~~~~~~~^~~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:265:43: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline void iosys_map_clear(struct iosys_map *map)
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_clear':
include/linux/iosys-map.h:267:24: error: dereferencing pointer to incomplete type 'struct iosys_map'
memset(map, 0, sizeof(*map));
^~~~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:281:47: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t dst_offset,
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_memcpy_to':
include/linux/iosys-map.h:284:9: error: dereferencing pointer to incomplete type 'struct iosys_map'
if (dst->is_iomem)
^~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:301:66: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline void iosys_map_memcpy_from(void *dst, const struct iosys_map *src,
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_memcpy_from':
include/linux/iosys-map.h:304:9: error: dereferencing pointer to incomplete type 'const struct iosys_map'
if (src->is_iomem)
^~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:318:42: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline void iosys_map_incr(struct iosys_map *map, size_t incr)
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_incr':
include/linux/iosys-map.h:320:9: error: dereferencing pointer to incomplete type 'struct iosys_map'
if (map->is_iomem)
^~
include/linux/iosys-map.h: At top level:
include/linux/iosys-map.h:336:44: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
static inline void iosys_map_memset(struct iosys_map *dst, size_t offset,
^~~~~~~~~
include/linux/iosys-map.h: In function 'iosys_map_memset':
include/linux/iosys-map.h:339:9: error: dereferencing pointer to incomplete type 'struct iosys_map'
if (dst->is_iomem)
^~
In file included from include/drm/drm_gem.h:38,
from drivers/gpu/drm/mgag200/mgag200_drv.h:18,
from drivers/gpu/drm/mgag200/mgag200_bmc.c:10:
include/linux/dma-buf.h: At top level:
>> include/linux/dma-buf.h:277:45: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map);
^~~~~~~~~
include/linux/dma-buf.h:278:48: warning: 'struct iosys_map' declared inside parameter list will not be visible outside of this definition or declaration
void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map);
^~~~~~~~~
>> include/linux/dma-buf.h:332:19: error: field 'vmap_ptr' has incomplete type
struct iosys_map vmap_ptr;
^~~~~~~~
cc1: some warnings being treated as errors
--
In file included from drivers/gpu/drm/mgag200/mgag200_drv.h:13,
from drivers/gpu/drm/mgag200/mgag200_ddc.c:36:
>> include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
--
In file included from drivers/gpu/drm/mgag200/mgag200_drv.h:13,
from drivers/gpu/drm/mgag200/mgag200_drv.c:25:
>> include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
In file included from include/linux/dma-buf.h:16,
from include/drm/drm_gem.h:38,
from drivers/gpu/drm/mgag200/mgag200_drv.h:18,
from drivers/gpu/drm/mgag200/mgag200_drv.c:25:
include/linux/iosys-map.h: In function 'iosys_map_set_vaddr':
>> include/linux/iosys-map.h:185:5: error: dereferencing pointer to incomplete type 'struct iosys_map'
map->vaddr = vaddr;
^~
include/linux/iosys-map.h: In function 'iosys_map_is_equal':
>> include/linux/iosys-map.h:217:9: error: dereferencing pointer to incomplete type 'const struct iosys_map'
if (lhs->is_iomem != rhs->is_iomem)
^~
In file included from include/drm/drm_gem.h:38,
from drivers/gpu/drm/mgag200/mgag200_drv.h:18,
from drivers/gpu/drm/mgag200/mgag200_drv.c:25:
include/linux/dma-buf.h: At top level:
>> include/linux/dma-buf.h:332:19: error: field 'vmap_ptr' has incomplete type
struct iosys_map vmap_ptr;
^~~~~~~~
--
In file included from drivers/gpu/drm/tiny/bochs.c:29:
>> include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
In file included from include/linux/module.h:23,
from drivers/gpu/drm/tiny/bochs.c:5:
drivers/gpu/drm/tiny/bochs.c: In function '__check_modeset':
>> drivers/gpu/drm/tiny/bochs.c:66:29: error: 'bochs_modeset' undeclared (first use in this function); did you mean 'drm_mode_set'?
module_param_named(modeset, bochs_modeset, int, 0444);
^~~~~~~~~~~~~
include/linux/moduleparam.h:430:68: note: in definition of macro '__param_check'
static inline type __always_unused *__check_##name(void) { return(p); }
^
include/linux/moduleparam.h:155:2: note: in expansion of macro 'param_check_int'
param_check_##type(name, &(value)); \
^~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:66:1: note: in expansion of macro 'module_param_named'
module_param_named(modeset, bochs_modeset, int, 0444);
^~~~~~~~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:66:29: note: each undeclared identifier is reported only once for each function it appears in
module_param_named(modeset, bochs_modeset, int, 0444);
^~~~~~~~~~~~~
include/linux/moduleparam.h:430:68: note: in definition of macro '__param_check'
static inline type __always_unused *__check_##name(void) { return(p); }
^
include/linux/moduleparam.h:155:2: note: in expansion of macro 'param_check_int'
param_check_##type(name, &(value)); \
^~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:66:1: note: in expansion of macro 'module_param_named'
module_param_named(modeset, bochs_modeset, int, 0444);
^~~~~~~~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c: At top level:
>> drivers/gpu/drm/tiny/bochs.c:66:29: error: 'bochs_modeset' undeclared here (not in a function); did you mean 'drm_mode_set'?
module_param_named(modeset, bochs_modeset, int, 0444);
^~~~~~~~~~~~~
include/linux/moduleparam.h:298:54: note: in definition of macro '__module_param_call'
VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } }
^~~
include/linux/moduleparam.h:156:2: note: in expansion of macro 'module_param_cb'
module_param_cb(name, ¶m_ops_##type, &value, perm); \
^~~~~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:66:1: note: in expansion of macro 'module_param_named'
module_param_named(modeset, bochs_modeset, int, 0444);
^~~~~~~~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c: In function 'bochs_pci_driver_init':
drivers/gpu/drm/tiny/bochs.c:835:1: warning: control reaches end of non-void function [-Wreturn-type]
drm_module_pci_driver_if_modeset(bochs_pci_driver, bochs_modeset);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
..
vim +489 include/video/vga.h
487
488 #endif /* __linux_video_vga_h__ */
> 489 ?
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH 14/19] video/vga: Add VGA_IS0_R
From: kernel test robot @ 2025-12-08 21:18 UTC (permalink / raw)
To: Ville Syrjala, intel-gfx
Cc: llvm, oe-kbuild-all, intel-xe, Helge Deller, linux-fbdev,
dri-devel
In-Reply-To: <20251208182637.334-15-ville.syrjala@linux.intel.com>
Hi Ville,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-tip/drm-tip]
[cannot apply to drm-i915/for-linux-next drm-i915/for-linux-next-fixes linus/master v6.18 next-20251208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Ville-Syrjala/drm-i915-vga-Register-vgaarb-client-later/20251209-030730
base: https://gitlab.freedesktop.org/drm/tip.git drm-tip
patch link: https://lore.kernel.org/r/20251208182637.334-15-ville.syrjala%40linux.intel.com
patch subject: [PATCH 14/19] video/vga: Add VGA_IS0_R
config: x86_64-allnoconfig (https://download.01.org/0day-ci/archive/20251209/202512090554.7pZ9xOQ5-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251209/202512090554.7pZ9xOQ5-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512090554.7pZ9xOQ5-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/video/console/vgacon.c:51:
>> include/video/vga.h:489:1: error: expected identifier or '('
489 | ?
| ^
>> drivers/video/console/vgacon.c:126:25: error: use of undeclared identifier 'vga_lock'; did you mean 'pgd_lock'?
126 | raw_spin_lock_irqsave(&vga_lock, flags);
| ^~~~~~~~
| pgd_lock
include/linux/spinlock.h:266:26: note: expanded from macro 'raw_spin_lock_irqsave'
266 | _raw_spin_lock_irqsave(lock, flags); \
| ^
include/linux/spinlock_api_up.h:69:60: note: expanded from macro '_raw_spin_lock_irqsave'
69 | #define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags)
| ^
include/linux/spinlock_api_up.h:40:38: note: expanded from macro '__LOCK_IRQSAVE'
40 | do { local_irq_save(flags); __LOCK(lock); } while (0)
| ^
include/linux/spinlock_api_up.h:31:35: note: expanded from macro '__LOCK'
31 | do { preempt_disable(); ___LOCK(lock); } while (0)
| ^
include/linux/spinlock_api_up.h:28:32: note: expanded from macro '___LOCK'
28 | do { __acquire(lock); (void)(lock); } while (0)
| ^
arch/x86/include/asm/pgtable.h:58:19: note: 'pgd_lock' declared here
58 | extern spinlock_t pgd_lock;
| ^
drivers/video/console/vgacon.c:131:30: error: use of undeclared identifier 'vga_lock'; did you mean 'pgd_lock'?
131 | raw_spin_unlock_irqrestore(&vga_lock, flags);
| ^~~~~~~~
| pgd_lock
include/linux/spinlock.h:282:31: note: expanded from macro 'raw_spin_unlock_irqrestore'
282 | _raw_spin_unlock_irqrestore(lock, flags); \
| ^
include/linux/spinlock_api_up.h:86:26: note: expanded from macro '_raw_spin_unlock_irqrestore'
86 | __UNLOCK_IRQRESTORE(lock, flags)
| ^
include/linux/spinlock_api_up.h:56:43: note: expanded from macro '__UNLOCK_IRQRESTORE'
56 | do { local_irq_restore(flags); __UNLOCK(lock); } while (0)
| ^
include/linux/spinlock_api_up.h:46:36: note: expanded from macro '__UNLOCK'
46 | do { preempt_enable(); ___UNLOCK(lock); } while (0)
| ^
include/linux/spinlock_api_up.h:43:32: note: expanded from macro '___UNLOCK'
43 | do { __release(lock); (void)(lock); } while (0)
| ^
arch/x86/include/asm/pgtable.h:58:19: note: 'pgd_lock' declared here
58 | extern spinlock_t pgd_lock;
| ^
drivers/video/console/vgacon.c:485:25: error: use of undeclared identifier 'vga_lock'; did you mean 'pgd_lock'?
485 | raw_spin_lock_irqsave(&vga_lock, flags);
| ^~~~~~~~
| pgd_lock
include/linux/spinlock.h:266:26: note: expanded from macro 'raw_spin_lock_irqsave'
266 | _raw_spin_lock_irqsave(lock, flags); \
| ^
include/linux/spinlock_api_up.h:69:60: note: expanded from macro '_raw_spin_lock_irqsave'
69 | #define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags)
| ^
include/linux/spinlock_api_up.h:40:38: note: expanded from macro '__LOCK_IRQSAVE'
40 | do { local_irq_save(flags); __LOCK(lock); } while (0)
| ^
include/linux/spinlock_api_up.h:31:35: note: expanded from macro '__LOCK'
31 | do { preempt_disable(); ___LOCK(lock); } while (0)
| ^
include/linux/spinlock_api_up.h:28:32: note: expanded from macro '___LOCK'
28 | do { __acquire(lock); (void)(lock); } while (0)
| ^
arch/x86/include/asm/pgtable.h:58:19: note: 'pgd_lock' declared here
58 | extern spinlock_t pgd_lock;
| ^
drivers/video/console/vgacon.c:503:30: error: use of undeclared identifier 'vga_lock'; did you mean 'pgd_lock'?
503 | raw_spin_unlock_irqrestore(&vga_lock, flags);
| ^~~~~~~~
| pgd_lock
include/linux/spinlock.h:282:31: note: expanded from macro 'raw_spin_unlock_irqrestore'
282 | _raw_spin_unlock_irqrestore(lock, flags); \
| ^
include/linux/spinlock_api_up.h:86:26: note: expanded from macro '_raw_spin_unlock_irqrestore'
86 | __UNLOCK_IRQRESTORE(lock, flags)
| ^
include/linux/spinlock_api_up.h:56:43: note: expanded from macro '__UNLOCK_IRQRESTORE'
56 | do { local_irq_restore(flags); __UNLOCK(lock); } while (0)
| ^
include/linux/spinlock_api_up.h:46:36: note: expanded from macro '__UNLOCK'
46 | do { preempt_enable(); ___UNLOCK(lock); } while (0)
| ^
include/linux/spinlock_api_up.h:43:32: note: expanded from macro '___UNLOCK'
43 | do { __release(lock); (void)(lock); } while (0)
| ^
arch/x86/include/asm/pgtable.h:58:19: note: 'pgd_lock' declared here
58 | extern spinlock_t pgd_lock;
| ^
drivers/video/console/vgacon.c:563:25: error: use of undeclared identifier 'vga_lock'; did you mean 'pgd_lock'?
563 | raw_spin_lock_irqsave(&vga_lock, flags);
| ^~~~~~~~
| pgd_lock
include/linux/spinlock.h:266:26: note: expanded from macro 'raw_spin_lock_irqsave'
266 | _raw_spin_lock_irqsave(lock, flags); \
| ^
include/linux/spinlock_api_up.h:69:60: note: expanded from macro '_raw_spin_lock_irqsave'
69 | #define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags)
| ^
include/linux/spinlock_api_up.h:40:38: note: expanded from macro '__LOCK_IRQSAVE'
40 | do { local_irq_save(flags); __LOCK(lock); } while (0)
| ^
vim +489 include/video/vga.h
487
488 #endif /* __linux_video_vga_h__ */
> 489 ?
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] riva/fbdev: fix divide error in nv3_arb()
From: Helge Deller @ 2025-12-08 22:02 UTC (permalink / raw)
To: Guangshuo Li, Antonino Daplas, linux-fbdev, dri-devel,
linux-kernel; +Cc: stable
In-Reply-To: <20251207072532.518547-1-lgs201920130244@gmail.com>
On 12/7/25 08:25, Guangshuo Li wrote:
> A userspace program can trigger the RIVA NV3 arbitration code by
> calling the FBIOPUT_VSCREENINFO ioctl on /dev/fb*. When doing so,
> the driver recomputes FIFO arbitration parameters in nv3_arb(), using
> state->mclk_khz (derived from the PRAMDAC MCLK PLL) as a divisor
> without validating it first.
>
> In a normal setup, state->mclk_khz is provided by the real hardware
> and is non-zero. However, an attacker can construct a malicious or
> misconfigured device (e.g. a crafted/emulated PCI device) that exposes
> a bogus PLL configuration, causing state->mclk_khz to become zero.
> Once nv3_get_param() calls nv3_arb(), the division by state->mclk_khz in
> the gns calculation causes a divide error and crashes the kernel.
>
> Fix this by checking whether state->mclk_khz is zero and bailing out before doing the division.
>
> The following log reveals it:
>
> rivafb: setting virtual Y resolution to 2184
> divide error: 0000 [#1] PREEMPT SMP KASAN PTI
> CPU: 0 PID: 2187 Comm: syz-executor.0 Not tainted 5.18.0-rc1+ #1
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014
> RIP: 0010:nv3_arb drivers/video/fbdev/riva/riva_hw.c:439 [inline]
> RIP: 0010:nv3_get_param+0x3ab/0x13b0 drivers/video/fbdev/riva/riva_hw.c:546
> Code: c1 e8 03 42 0f b6 14 38 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 08 84 d2 0f 85 b7 0e 00 00 41 8b 46 18 01 d8 69 c0 40 42 0f 00 99 <41> f7 fc 48 63 c8 4c 89 e8 48 c1 e8 03 42 0f b6 14 38 4c 89 e8 83
> RSP: 0018:ffff888013b2f318 EFLAGS: 00010206
> RAX: 0000000001d905c0 RBX: 0000000000000016 RCX: 0000000000040000
> RDX: 0000000000000000 RSI: 0000000000000080 RDI: ffff888013b2f6f0
> RBP: 0000000000000002 R08: ffffffff82226288 R09: 0000000000000001
> R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000000
> R13: ffff888013b2f4d8 R14: ffff888013b2f6d8 R15: dffffc0000000000
> Call Trace:
> nv3CalcArbitration.constprop.0+0x255/0x460 drivers/video/fbdev/riva/riva_hw.c:603
> nv3UpdateArbitrationSettings drivers/video/fbdev/riva/riva_hw.c:637 [inline]
> CalcStateExt+0x447/0x1b90 drivers/video/fbdev/riva/riva_hw.c:1246
> riva_load_video_mode+0x8a9/0xea0 drivers/video/fbdev/riva/fbdev.c:779
> rivafb_set_par+0xc0/0x5f0 drivers/video/fbdev/riva/fbdev.c:1196
Doesn't it make sense to check mclk_khz (or the various variables which
lead to mclk_khz) in rivafb_set_par() or any of the other functions mentioned
in this trace?
If in doubt, mclk_khz could be initialized to a sane value?
Helge
> fb_set_var+0x604/0xeb0 drivers/video/fbdev/core/fbmem.c:1033
> do_fb_ioctl+0x234/0x670 drivers/video/fbdev/core/fbmem.c:1109
> fb_ioctl+0xdd/0x130 drivers/video/fbdev/core/fbmem.c:1188
> __x64_sys_ioctl+0x122/0x190 fs/ioctl.c:856
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
> ---
> drivers/video/fbdev/riva/riva_hw.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/video/fbdev/riva/riva_hw.c b/drivers/video/fbdev/riva/riva_hw.c
> index 8b829b720064..d70c6c4d28e8 100644
> --- a/drivers/video/fbdev/riva/riva_hw.c
> +++ b/drivers/video/fbdev/riva/riva_hw.c
> @@ -436,6 +436,9 @@ static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state, nv3_arb_in
> vmisses = 2;
> eburst_size = state->memory_width * 1;
> mburst_size = 32;
> + if (!state->mclk_khz)
> + return (0);
> +
> gns = 1000000 * (gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
> ainfo->by_gfacc = gns*ainfo->gdrain_rate/1000000;
> ainfo->wcmocc = 0;
^ permalink raw reply
* Re: [PATCH 14/19] video/vga: Add VGA_IS0_R
From: kernel test robot @ 2025-12-08 22:22 UTC (permalink / raw)
To: Ville Syrjala, intel-gfx
Cc: oe-kbuild-all, intel-xe, Helge Deller, linux-fbdev, dri-devel
In-Reply-To: <20251208182637.334-15-ville.syrjala@linux.intel.com>
Hi Ville,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-tip/drm-tip]
[cannot apply to drm-i915/for-linux-next drm-i915/for-linux-next-fixes linus/master v6.18 next-20251208]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Ville-Syrjala/drm-i915-vga-Register-vgaarb-client-later/20251209-030730
base: https://gitlab.freedesktop.org/drm/tip.git drm-tip
patch link: https://lore.kernel.org/r/20251208182637.334-15-ville.syrjala%40linux.intel.com
patch subject: [PATCH 14/19] video/vga: Add VGA_IS0_R
config: i386-randconfig-141-20251209 (https://download.01.org/0day-ci/archive/20251209/202512090603.ycfxEuHJ-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251209/202512090603.ycfxEuHJ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512090603.ycfxEuHJ-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/gpu/drm/tiny/bochs.c:29:
include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
489 | ?
| ^
In file included from include/linux/module.h:23,
from drivers/gpu/drm/tiny/bochs.c:5:
drivers/gpu/drm/tiny/bochs.c: In function '__check_modeset':
drivers/gpu/drm/tiny/bochs.c:66:29: error: 'bochs_modeset' undeclared (first use in this function)
66 | module_param_named(modeset, bochs_modeset, int, 0444);
| ^~~~~~~~~~~~~
include/linux/moduleparam.h:430:75: note: in definition of macro '__param_check'
430 | static inline type __always_unused *__check_##name(void) { return(p); }
| ^
include/linux/moduleparam.h:155:9: note: in expansion of macro 'param_check_int'
155 | param_check_##type(name, &(value)); \
| ^~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:66:1: note: in expansion of macro 'module_param_named'
66 | module_param_named(modeset, bochs_modeset, int, 0444);
| ^~~~~~~~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:66:29: note: each undeclared identifier is reported only once for each function it appears in
66 | module_param_named(modeset, bochs_modeset, int, 0444);
| ^~~~~~~~~~~~~
include/linux/moduleparam.h:430:75: note: in definition of macro '__param_check'
430 | static inline type __always_unused *__check_##name(void) { return(p); }
| ^
include/linux/moduleparam.h:155:9: note: in expansion of macro 'param_check_int'
155 | param_check_##type(name, &(value)); \
| ^~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:66:1: note: in expansion of macro 'module_param_named'
66 | module_param_named(modeset, bochs_modeset, int, 0444);
| ^~~~~~~~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c: At top level:
drivers/gpu/drm/tiny/bochs.c:66:29: error: 'bochs_modeset' undeclared here (not in a function)
66 | module_param_named(modeset, bochs_modeset, int, 0444);
| ^~~~~~~~~~~~~
include/linux/moduleparam.h:298:61: note: in definition of macro '__module_param_call'
298 | VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } }
| ^~~
include/linux/moduleparam.h:156:9: note: in expansion of macro 'module_param_cb'
156 | module_param_cb(name, ¶m_ops_##type, &value, perm); \
| ^~~~~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:66:1: note: in expansion of macro 'module_param_named'
66 | module_param_named(modeset, bochs_modeset, int, 0444);
| ^~~~~~~~~~~~~~~~~~
In file included from include/linux/device.h:32,
from include/linux/pci.h:37,
from drivers/gpu/drm/tiny/bochs.c:6:
drivers/gpu/drm/tiny/bochs.c: In function 'bochs_pci_driver_init':
>> include/linux/device/driver.h:261:1: warning: control reaches end of non-void function [-Wreturn-type]
261 | } \
| ^
include/drm/drm_module.h:93:9: note: in expansion of macro 'module_driver'
93 | module_driver(__pci_drv, drm_pci_register_driver_if_modeset, \
| ^~~~~~~~~~~~~
drivers/gpu/drm/tiny/bochs.c:835:1: note: in expansion of macro 'drm_module_pci_driver_if_modeset'
835 | drm_module_pci_driver_if_modeset(bochs_pci_driver, bochs_modeset);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +261 include/linux/device/driver.h
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 242
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 243 /**
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 244 * module_driver() - Helper macro for drivers that don't do anything
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 245 * special in module init/exit. This eliminates a lot of boilerplate.
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 246 * Each module may only use this macro once, and calling it replaces
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 247 * module_init() and module_exit().
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 248 *
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 249 * @__driver: driver name
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 250 * @__register: register function for this driver type
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 251 * @__unregister: unregister function for this driver type
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 252 * @...: Additional arguments to be passed to __register and __unregister.
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 253 *
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 254 * Use this macro to construct bus specific macros for registering
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 255 * drivers, and do not use it on its own.
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 256 */
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 257 #define module_driver(__driver, __register, __unregister, ...) \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 258 static int __init __driver##_init(void) \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 259 { \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 260 return __register(&(__driver) , ##__VA_ARGS__); \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 @261 } \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 262 module_init(__driver##_init); \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 263 static void __exit __driver##_exit(void) \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 264 { \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 265 __unregister(&(__driver) , ##__VA_ARGS__); \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 266 } \
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 267 module_exit(__driver##_exit);
4c002c978b7f2f Greg Kroah-Hartman 2019-12-09 268
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH 0/3] fbdev: Guard sysfs interfaces under CONFIG_FB_DEVICE
From: Chintan Patel @ 2025-12-09 4:27 UTC (permalink / raw)
To: linux-fbdev, linux-staging, linux-omap
Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
Chintan Patel
Hi all,
This small series makes several legacy fbdev drivers buildable with
CONFIG_FB_DEVICE=n. Currently, multiple fbdev drivers rely on fb_info->dev
and sysfs attribute registration unconditionally, which leads to build
failures whenever FB_DEVICE is disabled.
Thomas previously noted that FB_DEVICE should eventually become optional
and that drivers should not depend on sysfs or fb_info->dev being present
unless the Kconfig explicitly selects it. This series pushes in that
direction by tightening the FB_DEVICE dependency boundary without changing
any runtime behaviour when FB_DEVICE=y.
What this series does *not* change
- No functional behaviour changes when FB_DEVICE=y.
- No removal of sysfs interfaces.
- No changes to fbops, memory allocation, or display update paths.
Build & test coverage
Tested with the following combinations:
1. **FB=y, FB_DEVICE=y**
- Baseline configuration; no regressions expected.
2. **FB=y, FB_DEVICE=n**
- Drivers build successfully.
- No sysfs attributes are created.
- fbdev devices operate normally (where applicable).
3. **FB=n**
- Drivers depend on FB, so they properly do not build, unchanged.
Motivation
This moves fbdev closer to supporting FB_DEVICE as truly optional, helps
reduce Kconfig entanglement, and clears several long-standing TODO items
as suggested by Thomas Zimmermann around legacy sysfs usage inside fbdev
drivers.
Feedback is welcome, especially on whether the guard boundaries around
sysfs are placed correctly or whether more logic should be pulled under
CONFIG_FB_DEVICE.
Thanks,
Chintan
Chintan Patel (3):
fbtft: Make sysfs and dev_*() logging conditional on FB_DEVICE
omapfb: Guard sysfs code under CONFIG_FB_DEVICE
sh_mobile_lcdc: Guard overlay sysfs interfaces under CONFIG_FB_DEVICE
drivers/staging/fbtft/fbtft-core.c | 20 +++++++++++++++++--
drivers/staging/fbtft/fbtft-sysfs.c | 8 ++++++++
drivers/video/fbdev/omap2/omapfb/Kconfig | 2 +-
.../video/fbdev/omap2/omapfb/omapfb-sysfs.c | 11 ++++++++++
drivers/video/fbdev/sh_mobile_lcdcfb.c | 4 ++++
5 files changed, 42 insertions(+), 3 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH 1/3] fbtft: Make sysfs and dev_*() logging conditional on FB_DEVICE
From: Chintan Patel @ 2025-12-09 4:27 UTC (permalink / raw)
To: linux-fbdev, linux-staging, linux-omap
Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
Chintan Patel
In-Reply-To: <20251209042744.7875-1-chintanlike@gmail.com>
The fbtft core and sysfs implementation unconditionally dereference
fb_info->dev and register sysfs attributes. When FB_DEVICE=n, these
fields are unavailable, leading to build failures.
This patch wraps all sysfs attribute creation/removal and dev_dbg/dev_info
logging in #ifdef CONFIG_FB_DEVICE, with pr_*() fallbacks for the
non-FB_DEVICE case. This makes fbtft fully buildable when FB_DEVICE is
disabled.
Signed-off-by: Chintan Patel <chintanlike@gmail.com>
---
drivers/staging/fbtft/fbtft-core.c | 20 ++++++++++++++++++--
drivers/staging/fbtft/fbtft-sysfs.c | 8 ++++++++
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 9e7b84071174..dc967bdeabe8 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -365,9 +365,14 @@ static int fbtft_fb_setcolreg(unsigned int regno, unsigned int red,
unsigned int val;
int ret = 1;
+#ifdef CONFIG_FB_DEVICE
dev_dbg(info->dev,
"%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n",
__func__, regno, red, green, blue, transp);
+#else
+ pr_debug("%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n",
+ __func__, regno, red, green, blue, transp);
+#endif
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
@@ -391,8 +396,11 @@ static int fbtft_fb_blank(int blank, struct fb_info *info)
struct fbtft_par *par = info->par;
int ret = -EINVAL;
- dev_dbg(info->dev, "%s(blank=%d)\n",
- __func__, blank);
+#ifdef CONFIG_FB_DEVICE
+ dev_dbg(info->dev, "%s(blank=%d)\n", __func__, blank);
+#else
+ pr_debug("%s(blank=%d)\n", __func__, blank);
+#endif
if (!par->fbtftops.blank)
return ret;
@@ -793,6 +801,8 @@ int fbtft_register_framebuffer(struct fb_info *fb_info)
if (spi)
sprintf(text2, ", spi%d.%d at %d MHz", spi->controller->bus_num,
spi_get_chipselect(spi, 0), spi->max_speed_hz / 1000000);
+
+#ifdef CONFIG_FB_DEVICE
dev_info(fb_info->dev,
"%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n",
fb_info->fix.id, fb_info->var.xres, fb_info->var.yres,
@@ -804,6 +814,12 @@ int fbtft_register_framebuffer(struct fb_info *fb_info)
fb_info->bl_dev->props.power = BACKLIGHT_POWER_ON;
fb_info->bl_dev->ops->update_status(fb_info->bl_dev);
}
+#else
+ pr_info("%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n",
+ fb_info->fix.id, fb_info->var.xres, fb_info->var.yres,
+ fb_info->fix.smem_len >> 10, text1,
+ HZ / fb_info->fbdefio->delay, text2);
+#endif
return 0;
diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c
index e45c90a03a90..944f74f592d0 100644
--- a/drivers/staging/fbtft/fbtft-sysfs.c
+++ b/drivers/staging/fbtft/fbtft-sysfs.c
@@ -89,6 +89,7 @@ int fbtft_gamma_parse_str(struct fbtft_par *par, u32 *curves,
return ret;
}
+#ifdef CONFIG_FB_DEVICE
static ssize_t
sprintf_gamma(struct fbtft_par *par, u32 *curves, char *buf)
{
@@ -145,6 +146,7 @@ static ssize_t show_gamma_curve(struct device *device,
static struct device_attribute gamma_device_attrs[] = {
__ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve),
};
+#endif
void fbtft_expand_debug_value(unsigned long *debug)
{
@@ -173,6 +175,7 @@ void fbtft_expand_debug_value(unsigned long *debug)
}
}
+#ifdef CONFIG_FB_DEVICE
static ssize_t store_debug(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -200,17 +203,22 @@ static ssize_t show_debug(struct device *device,
static struct device_attribute debug_device_attr =
__ATTR(debug, 0660, show_debug, store_debug);
+#endif
void fbtft_sysfs_init(struct fbtft_par *par)
{
+#ifdef CONFIG_FB_DEVICE
device_create_file(par->info->dev, &debug_device_attr);
if (par->gamma.curves && par->fbtftops.set_gamma)
device_create_file(par->info->dev, &gamma_device_attrs[0]);
+#endif
}
void fbtft_sysfs_exit(struct fbtft_par *par)
{
+#ifdef CONFIG_FB_DEVICE
device_remove_file(par->info->dev, &debug_device_attr);
if (par->gamma.curves && par->fbtftops.set_gamma)
device_remove_file(par->info->dev, &gamma_device_attrs[0]);
+#endif
}
--
2.43.0
^ permalink raw reply related
* [PATCH 2/3] omapfb: Guard sysfs code under CONFIG_FB_DEVICE
From: Chintan Patel @ 2025-12-09 4:27 UTC (permalink / raw)
To: linux-fbdev, linux-staging, linux-omap
Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
Chintan Patel
In-Reply-To: <20251209042744.7875-1-chintanlike@gmail.com>
omapfb implements multiple sysfs attributes for framebuffer rotation,
overlays, and debug information. These interfaces depend on FB_DEVICE
being enabled.
This patch wraps all sysfs attribute definitions, registration, and
removal in #ifdef CONFIG_FB_DEVICE. For FB_DEVICE=n, lightweight stub
functions are provided so that the driver builds and runs without
exposing sysfs interfaces.
Signed-off-by: Chintan Patel <chintanlike@gmail.com>
---
drivers/video/fbdev/omap2/omapfb/Kconfig | 2 +-
drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c | 11 +++++++++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/video/fbdev/omap2/omapfb/Kconfig b/drivers/video/fbdev/omap2/omapfb/Kconfig
index f4cdf999a080..ee664decbb64 100644
--- a/drivers/video/fbdev/omap2/omapfb/Kconfig
+++ b/drivers/video/fbdev/omap2/omapfb/Kconfig
@@ -5,7 +5,6 @@ config OMAP2_VRFB
menuconfig FB_OMAP2
tristate "OMAP2+ frame buffer support"
depends on FB
- depends on FB_DEVICE
depends on DRM_OMAP = n
depends on GPIOLIB
select FB_OMAP2_DSS
@@ -13,6 +12,7 @@ menuconfig FB_OMAP2
select FB_IOMEM_HELPERS
help
Frame buffer driver for OMAP2+ based boards.
+ Selecting FB_DEVICE enables additional sysfs interfaces.
if FB_OMAP2
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
index 831b2c2fbdf9..0a340f69484f 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
@@ -24,6 +24,7 @@
#include "omapfb.h"
+#ifdef CONFIG_FB_DEVICE
static ssize_t show_rotate_type(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -585,4 +586,14 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
&omapfb_attrs[t]);
}
}
+#else
+int omapfb_create_sysfs(struct omapfb2_device *fbdev)
+{
+ return 0;
+}
+
+void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
+{
+}
+#endif
--
2.43.0
^ permalink raw reply related
* [PATCH 3/3] sh_mobile_lcdc: Guard overlay sysfs interfaces under CONFIG_FB_DEVICE
From: Chintan Patel @ 2025-12-09 4:27 UTC (permalink / raw)
To: linux-fbdev, linux-staging, linux-omap
Cc: linux-kernel, dri-devel, tzimmermann, andy, deller, gregkh,
Chintan Patel
In-Reply-To: <20251209042744.7875-1-chintanlike@gmail.com>
The SH Mobile LCDC driver exposes overlay configuration via sysfs.
These attributes depend on FB_DEVICE and cause build failures when
FB_DEVICE=n.
Wrap all overlay sysfs attribute definitions and group registrations
within CONFIG_FB_DEVICE. When FB_DEVICE is disabled, the driver still
loads but without sysfs entries.
Signed-off-by: Chintan Patel <chintanlike@gmail.com>
---
drivers/video/fbdev/sh_mobile_lcdcfb.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index dd950e4ab5ce..a46da10789c3 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -1182,6 +1182,7 @@ static int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
* Frame buffer operations - Overlays
*/
+#ifdef CONFIG_FB_DEVICE
static ssize_t
overlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -1351,6 +1352,7 @@ static struct attribute *overlay_sysfs_attrs[] = {
NULL,
};
ATTRIBUTE_GROUPS(overlay_sysfs);
+#endif
static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix = {
.id = "SH Mobile LCDC",
@@ -2637,7 +2639,9 @@ static int sh_mobile_lcdc_probe(struct platform_device *pdev)
static struct platform_driver sh_mobile_lcdc_driver = {
.driver = {
.name = "sh_mobile_lcdc_fb",
+#ifdef CONFIG_FB_DEVICE
.dev_groups = overlay_sysfs_groups,
+#endif
.pm = &sh_mobile_lcdc_dev_pm_ops,
},
.probe = sh_mobile_lcdc_probe,
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/3] fbtft: Make sysfs and dev_*() logging conditional on FB_DEVICE
From: Thomas Zimmermann @ 2025-12-09 7:25 UTC (permalink / raw)
To: Chintan Patel, linux-fbdev, linux-staging, linux-omap
Cc: linux-kernel, dri-devel, andy, deller, gregkh
In-Reply-To: <20251209042744.7875-2-chintanlike@gmail.com>
Hi
Am 09.12.25 um 05:27 schrieb Chintan Patel:
> The fbtft core and sysfs implementation unconditionally dereference
> fb_info->dev and register sysfs attributes. When FB_DEVICE=n, these
> fields are unavailable, leading to build failures.
>
> This patch wraps all sysfs attribute creation/removal and dev_dbg/dev_info
> logging in #ifdef CONFIG_FB_DEVICE, with pr_*() fallbacks for the
> non-FB_DEVICE case. This makes fbtft fully buildable when FB_DEVICE is
> disabled.
>
> Signed-off-by: Chintan Patel <chintanlike@gmail.com>
> ---
> drivers/staging/fbtft/fbtft-core.c | 20 ++++++++++++++++++--
> drivers/staging/fbtft/fbtft-sysfs.c | 8 ++++++++
> 2 files changed, 26 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
> index 9e7b84071174..dc967bdeabe8 100644
> --- a/drivers/staging/fbtft/fbtft-core.c
> +++ b/drivers/staging/fbtft/fbtft-core.c
> @@ -365,9 +365,14 @@ static int fbtft_fb_setcolreg(unsigned int regno, unsigned int red,
> unsigned int val;
> int ret = 1;
>
> +#ifdef CONFIG_FB_DEVICE
> dev_dbg(info->dev,
Rather use fb_dbg() [1] and similar helpers for logging. They only need
the info pointer and do the correct output by themselves.
[1] https://elixir.bootlin.com/linux/v6.18/source/include/linux/fb.h#L895
> "%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n",
> __func__, regno, red, green, blue, transp);
> +#else
> + pr_debug("%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n",
> + __func__, regno, red, green, blue, transp);
> +#endif
>
> switch (info->fix.visual) {
> case FB_VISUAL_TRUECOLOR:
> @@ -391,8 +396,11 @@ static int fbtft_fb_blank(int blank, struct fb_info *info)
> struct fbtft_par *par = info->par;
> int ret = -EINVAL;
>
> - dev_dbg(info->dev, "%s(blank=%d)\n",
> - __func__, blank);
> +#ifdef CONFIG_FB_DEVICE
> + dev_dbg(info->dev, "%s(blank=%d)\n", __func__, blank);
> +#else
> + pr_debug("%s(blank=%d)\n", __func__, blank);
> +#endif
>
> if (!par->fbtftops.blank)
> return ret;
> @@ -793,6 +801,8 @@ int fbtft_register_framebuffer(struct fb_info *fb_info)
> if (spi)
> sprintf(text2, ", spi%d.%d at %d MHz", spi->controller->bus_num,
> spi_get_chipselect(spi, 0), spi->max_speed_hz / 1000000);
> +
> +#ifdef CONFIG_FB_DEVICE
> dev_info(fb_info->dev,
Same here with fb_info().
Best regards
Thomas
> "%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n",
> fb_info->fix.id, fb_info->var.xres, fb_info->var.yres,
> @@ -804,6 +814,12 @@ int fbtft_register_framebuffer(struct fb_info *fb_info)
> fb_info->bl_dev->props.power = BACKLIGHT_POWER_ON;
> fb_info->bl_dev->ops->update_status(fb_info->bl_dev);
> }
> +#else
> + pr_info("%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n",
> + fb_info->fix.id, fb_info->var.xres, fb_info->var.yres,
> + fb_info->fix.smem_len >> 10, text1,
> + HZ / fb_info->fbdefio->delay, text2);
> +#endif
>
> return 0;
>
> diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c
> index e45c90a03a90..944f74f592d0 100644
> --- a/drivers/staging/fbtft/fbtft-sysfs.c
> +++ b/drivers/staging/fbtft/fbtft-sysfs.c
> @@ -89,6 +89,7 @@ int fbtft_gamma_parse_str(struct fbtft_par *par, u32 *curves,
> return ret;
> }
>
> +#ifdef CONFIG_FB_DEVICE
> static ssize_t
> sprintf_gamma(struct fbtft_par *par, u32 *curves, char *buf)
> {
> @@ -145,6 +146,7 @@ static ssize_t show_gamma_curve(struct device *device,
> static struct device_attribute gamma_device_attrs[] = {
> __ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve),
> };
> +#endif
>
> void fbtft_expand_debug_value(unsigned long *debug)
> {
> @@ -173,6 +175,7 @@ void fbtft_expand_debug_value(unsigned long *debug)
> }
> }
>
> +#ifdef CONFIG_FB_DEVICE
> static ssize_t store_debug(struct device *device,
> struct device_attribute *attr,
> const char *buf, size_t count)
> @@ -200,17 +203,22 @@ static ssize_t show_debug(struct device *device,
>
> static struct device_attribute debug_device_attr =
> __ATTR(debug, 0660, show_debug, store_debug);
> +#endif
>
> void fbtft_sysfs_init(struct fbtft_par *par)
> {
> +#ifdef CONFIG_FB_DEVICE
> device_create_file(par->info->dev, &debug_device_attr);
> if (par->gamma.curves && par->fbtftops.set_gamma)
> device_create_file(par->info->dev, &gamma_device_attrs[0]);
> +#endif
> }
>
> void fbtft_sysfs_exit(struct fbtft_par *par)
> {
> +#ifdef CONFIG_FB_DEVICE
> device_remove_file(par->info->dev, &debug_device_attr);
> if (par->gamma.curves && par->fbtftops.set_gamma)
> device_remove_file(par->info->dev, &gamma_device_attrs[0]);
> +#endif
> }
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)
^ permalink raw reply
* Re: [PATCH 0/3] fbdev: Guard sysfs interfaces under CONFIG_FB_DEVICE
From: Thomas Zimmermann @ 2025-12-09 7:27 UTC (permalink / raw)
To: Chintan Patel, linux-fbdev, linux-staging, linux-omap
Cc: linux-kernel, dri-devel, andy, deller, gregkh
In-Reply-To: <20251209042744.7875-1-chintanlike@gmail.com>
Hi
Am 09.12.25 um 05:27 schrieb Chintan Patel:
> Hi all,
>
> This small series makes several legacy fbdev drivers buildable with
> CONFIG_FB_DEVICE=n. Currently, multiple fbdev drivers rely on fb_info->dev
> and sysfs attribute registration unconditionally, which leads to build
> failures whenever FB_DEVICE is disabled.
>
> Thomas previously noted that FB_DEVICE should eventually become optional
> and that drivers should not depend on sysfs or fb_info->dev being present
> unless the Kconfig explicitly selects it. This series pushes in that
> direction by tightening the FB_DEVICE dependency boundary without changing
> any runtime behaviour when FB_DEVICE=y.
>
> What this series does *not* change
>
> - No functional behaviour changes when FB_DEVICE=y.
> - No removal of sysfs interfaces.
> - No changes to fbops, memory allocation, or display update paths.
>
> Build & test coverage
>
> Tested with the following combinations:
>
> 1. **FB=y, FB_DEVICE=y**
> - Baseline configuration; no regressions expected.
>
> 2. **FB=y, FB_DEVICE=n**
> - Drivers build successfully.
> - No sysfs attributes are created.
> - fbdev devices operate normally (where applicable).
>
> 3. **FB=n**
> - Drivers depend on FB, so they properly do not build, unchanged.
>
> Motivation
>
> This moves fbdev closer to supporting FB_DEVICE as truly optional, helps
> reduce Kconfig entanglement, and clears several long-standing TODO items
> as suggested by Thomas Zimmermann around legacy sysfs usage inside fbdev
> drivers.
>
> Feedback is welcome, especially on whether the guard boundaries around
> sysfs are placed correctly or whether more logic should be pulled under
> CONFIG_FB_DEVICE.
I left a comment on the first patch. If things still build nicely, then
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
for the series.
Best regards
Thomas
>
> Thanks,
> Chintan
>
> Chintan Patel (3):
> fbtft: Make sysfs and dev_*() logging conditional on FB_DEVICE
> omapfb: Guard sysfs code under CONFIG_FB_DEVICE
> sh_mobile_lcdc: Guard overlay sysfs interfaces under CONFIG_FB_DEVICE
>
> drivers/staging/fbtft/fbtft-core.c | 20 +++++++++++++++++--
> drivers/staging/fbtft/fbtft-sysfs.c | 8 ++++++++
> drivers/video/fbdev/omap2/omapfb/Kconfig | 2 +-
> .../video/fbdev/omap2/omapfb/omapfb-sysfs.c | 11 ++++++++++
> drivers/video/fbdev/sh_mobile_lcdcfb.c | 4 ++++
> 5 files changed, 42 insertions(+), 3 deletions(-)
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)
^ permalink raw reply
* [PATCH v2 14/19] video/vga: Add VGA_IS0_R
From: Ville Syrjala @ 2025-12-09 7:55 UTC (permalink / raw)
To: intel-gfx; +Cc: intel-xe, Helge Deller, linux-fbdev, dri-devel
In-Reply-To: <20251208182637.334-15-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Add a proper name for the "Input status register 0" IO address.
Currently we have some code that does read addressed using the
aliasing VGA_MSR_W define, making it unclear what register we're
actually reading.
v2: Remove stray '?'
Cc: Helge Deller <deller@gmx.de>
Cc: linux-fbdev@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
include/video/vga.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/video/vga.h b/include/video/vga.h
index 468764d6727a..2f13c371800b 100644
--- a/include/video/vga.h
+++ b/include/video/vga.h
@@ -46,6 +46,7 @@
#define VGA_MIS_R 0x3CC /* Misc Output Read Register */
#define VGA_MIS_W 0x3C2 /* Misc Output Write Register */
#define VGA_FTC_R 0x3CA /* Feature Control Read Register */
+#define VGA_IS0_R 0x3C2 /* Input Status Register 0 */
#define VGA_IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
#define VGA_IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
#define VGA_PEL_D 0x3C9 /* PEL Data Register */
--
2.51.2
^ permalink raw reply related
* Re: [PATCH 0/3] fbdev: Guard sysfs interfaces under CONFIG_FB_DEVICE
From: Helge Deller @ 2025-12-09 8:22 UTC (permalink / raw)
To: Thomas Zimmermann, Chintan Patel, linux-fbdev, linux-staging,
linux-omap
Cc: linux-kernel, dri-devel, andy, gregkh
In-Reply-To: <19e8a1b0-75e3-4c8d-911a-15fd70f60bea@suse.de>
On 12/9/25 08:27, Thomas Zimmermann wrote:
> Hi
>
> Am 09.12.25 um 05:27 schrieb Chintan Patel:
>> Hi all,
>>
>> This small series makes several legacy fbdev drivers buildable with
>> CONFIG_FB_DEVICE=n. Currently, multiple fbdev drivers rely on fb_info->dev
>> and sysfs attribute registration unconditionally, which leads to build
>> failures whenever FB_DEVICE is disabled.
>>
>> Thomas previously noted that FB_DEVICE should eventually become optional
>> and that drivers should not depend on sysfs or fb_info->dev being present
>> unless the Kconfig explicitly selects it. This series pushes in that
>> direction by tightening the FB_DEVICE dependency boundary without changing
>> any runtime behaviour when FB_DEVICE=y.
>>
>> What this series does *not* change
>>
>> - No functional behaviour changes when FB_DEVICE=y.
>> - No removal of sysfs interfaces.
>> - No changes to fbops, memory allocation, or display update paths.
>>
>> Build & test coverage
>>
>> Tested with the following combinations:
>>
>> 1. **FB=y, FB_DEVICE=y**
>> - Baseline configuration; no regressions expected.
>>
>> 2. **FB=y, FB_DEVICE=n**
>> - Drivers build successfully.
>> - No sysfs attributes are created.
>> - fbdev devices operate normally (where applicable).
>>
>> 3. **FB=n**
>> - Drivers depend on FB, so they properly do not build, unchanged.
>>
>> Motivation
>>
>> This moves fbdev closer to supporting FB_DEVICE as truly optional, helps
>> reduce Kconfig entanglement, and clears several long-standing TODO items
>> as suggested by Thomas Zimmermann around legacy sysfs usage inside fbdev
>> drivers.
>>
>> Feedback is welcome, especially on whether the guard boundaries around
>> sysfs are placed correctly or whether more logic should be pulled under
>> CONFIG_FB_DEVICE.
>
> I left a comment on the first patch. If things still build nicely, then
>
> Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
>
> for the series.
This whole series adds a whole lot of ifdef'ery, which I think is the
worst approach. It makes the code less readable and leads to two code
paths, which may trigger different build errors depending on the config.
I'm sure it must be possible to do the same without adding more #ifdefs,
e.g. by introducing a function like dev_of_fbinfo(fbinfo) which
simply returns NULL for the FB_DEVICE=n case. Then, that value can be tested
like
if (dev_of_fbinfo(fbinfo))
{...do-the-things...}
For the FB_DEVICE=n case this will then be optimized out by the compiler,
while you still have full compiler syntax checking.
Thoughts?
Helge
^ permalink raw reply
* Re: [PATCH 0/3] fbdev: Guard sysfs interfaces under CONFIG_FB_DEVICE
From: Thomas Zimmermann @ 2025-12-09 8:42 UTC (permalink / raw)
To: Helge Deller, Chintan Patel, linux-fbdev, linux-staging,
linux-omap
Cc: linux-kernel, dri-devel, andy, gregkh
In-Reply-To: <f5d50007-5b48-47cb-8133-72fca274d562@gmx.de>
Hi
Am 09.12.25 um 09:22 schrieb Helge Deller:
> On 12/9/25 08:27, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 09.12.25 um 05:27 schrieb Chintan Patel:
>>> Hi all,
>>>
>>> This small series makes several legacy fbdev drivers buildable with
>>> CONFIG_FB_DEVICE=n. Currently, multiple fbdev drivers rely on
>>> fb_info->dev
>>> and sysfs attribute registration unconditionally, which leads to build
>>> failures whenever FB_DEVICE is disabled.
>>>
>>> Thomas previously noted that FB_DEVICE should eventually become
>>> optional
>>> and that drivers should not depend on sysfs or fb_info->dev being
>>> present
>>> unless the Kconfig explicitly selects it. This series pushes in that
>>> direction by tightening the FB_DEVICE dependency boundary without
>>> changing
>>> any runtime behaviour when FB_DEVICE=y.
>>>
>>> What this series does *not* change
>>>
>>> - No functional behaviour changes when FB_DEVICE=y.
>>> - No removal of sysfs interfaces.
>>> - No changes to fbops, memory allocation, or display update paths.
>>>
>>> Build & test coverage
>>>
>>> Tested with the following combinations:
>>>
>>> 1. **FB=y, FB_DEVICE=y**
>>> - Baseline configuration; no regressions expected.
>>>
>>> 2. **FB=y, FB_DEVICE=n**
>>> - Drivers build successfully.
>>> - No sysfs attributes are created.
>>> - fbdev devices operate normally (where applicable).
>>>
>>> 3. **FB=n**
>>> - Drivers depend on FB, so they properly do not build, unchanged.
>>>
>>> Motivation
>>>
>>> This moves fbdev closer to supporting FB_DEVICE as truly optional,
>>> helps
>>> reduce Kconfig entanglement, and clears several long-standing TODO
>>> items
>>> as suggested by Thomas Zimmermann around legacy sysfs usage inside
>>> fbdev
>>> drivers.
>>>
>>> Feedback is welcome, especially on whether the guard boundaries around
>>> sysfs are placed correctly or whether more logic should be pulled under
>>> CONFIG_FB_DEVICE.
>>
>> I left a comment on the first patch. If things still build nicely, then
>>
>> Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
>>
>> for the series.
>
> This whole series adds a whole lot of ifdef'ery, which I think is the
> worst approach. It makes the code less readable and leads to two code
> paths, which may trigger different build errors depending on the config.
>
> I'm sure it must be possible to do the same without adding more #ifdefs,
> e.g. by introducing a function like dev_of_fbinfo(fbinfo) which
> simply returns NULL for the FB_DEVICE=n case. Then, that value can be
> tested
> like
> if (dev_of_fbinfo(fbinfo))
> {...do-the-things...}
> For the FB_DEVICE=n case this will then be optimized out by the compiler,
> while you still have full compiler syntax checking.
>
> Thoughts?
Your choice. I don't see this as an important fix. The FB_DEVICE=n case
is mostly useful for DRM-based systems that do not want to expose fbdev
interfaces to user space. Those are the vast majority today. The very
few special builds with fbdev drivers would likely use FB_DEVICE=y anyway.
Best regards
Thomas
>
> Helge
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)
^ permalink raw reply
* Re: [PATCH] riva/fbdev: fix divide error in nv3_arb()
From: kernel test robot @ 2025-12-09 9:02 UTC (permalink / raw)
To: Guangshuo Li, Antonino Daplas, Helge Deller, linux-fbdev,
dri-devel, linux-kernel
Cc: oe-kbuild-all, Guangshuo Li, stable
In-Reply-To: <20251207072532.518547-1-lgs201920130244@gmail.com>
Hi Guangshuo,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on drm-tip/drm-tip linus/master v6.18 next-20251209]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Guangshuo-Li/riva-fbdev-fix-divide-error-in-nv3_arb/20251207-152840
base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next
patch link: https://lore.kernel.org/r/20251207072532.518547-1-lgs201920130244%40gmail.com
patch subject: [PATCH] riva/fbdev: fix divide error in nv3_arb()
config: x86_64-randconfig-161-20251209 (https://download.01.org/0day-ci/archive/20251209/202512091641.0Nz2KxpF-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512091641.0Nz2KxpF-lkp@intel.com/
New smatch warnings:
drivers/video/fbdev/riva/riva_hw.c:439 nv3_arb() warn: inconsistent indenting
Old smatch warnings:
drivers/video/fbdev/riva/riva_hw.c:982 nv10CalcArbitration() warn: inconsistent indenting
vim +439 drivers/video/fbdev/riva/riva_hw.c
154
155 typedef struct {
156 int gdrain_rate;
157 int vdrain_rate;
158 int mdrain_rate;
159 int gburst_size;
160 int vburst_size;
161 char vid_en;
162 char gr_en;
163 int wcmocc, wcgocc, wcvocc, wcvlwm, wcglwm;
164 int by_gfacc;
165 char vid_only_once;
166 char gr_only_once;
167 char first_vacc;
168 char first_gacc;
169 char first_macc;
170 int vocc;
171 int gocc;
172 int mocc;
173 char cur;
174 char engine_en;
175 char converged;
176 int priority;
177 } nv3_arb_info;
178 typedef struct {
179 int graphics_lwm;
180 int video_lwm;
181 int graphics_burst_size;
182 int video_burst_size;
183 int graphics_hi_priority;
184 int media_hi_priority;
185 int rtl_values;
186 int valid;
187 } nv3_fifo_info;
188 typedef struct {
189 char pix_bpp;
190 char enable_video;
191 char gr_during_vid;
192 char enable_mp;
193 int memory_width;
194 int video_scale;
195 int pclk_khz;
196 int mclk_khz;
197 int mem_page_miss;
198 int mem_latency;
199 char mem_aligned;
200 } nv3_sim_state;
201 typedef struct {
202 int graphics_lwm;
203 int video_lwm;
204 int graphics_burst_size;
205 int video_burst_size;
206 int valid;
207 } nv4_fifo_info;
208 typedef struct {
209 int pclk_khz;
210 int mclk_khz;
211 int nvclk_khz;
212 char mem_page_miss;
213 char mem_latency;
214 int memory_width;
215 char enable_video;
216 char gr_during_vid;
217 char pix_bpp;
218 char mem_aligned;
219 char enable_mp;
220 } nv4_sim_state;
221 typedef struct {
222 int graphics_lwm;
223 int video_lwm;
224 int graphics_burst_size;
225 int video_burst_size;
226 int valid;
227 } nv10_fifo_info;
228 typedef struct {
229 int pclk_khz;
230 int mclk_khz;
231 int nvclk_khz;
232 char mem_page_miss;
233 char mem_latency;
234 u32 memory_type;
235 int memory_width;
236 char enable_video;
237 char gr_during_vid;
238 char pix_bpp;
239 char mem_aligned;
240 char enable_mp;
241 } nv10_sim_state;
242 static int nv3_iterate(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
243 {
244 int iter = 0;
245 int tmp;
246 int vfsize, mfsize, gfsize;
247 int mburst_size = 32;
248 int mmisses, gmisses, vmisses;
249 int misses;
250 int vlwm, glwm;
251 int last, next, cur;
252 int max_gfsize ;
253 long ns;
254
255 vlwm = 0;
256 glwm = 0;
257 vfsize = 0;
258 gfsize = 0;
259 cur = ainfo->cur;
260 mmisses = 2;
261 gmisses = 2;
262 vmisses = 2;
263 if (ainfo->gburst_size == 128) max_gfsize = GFIFO_SIZE_128;
264 else max_gfsize = GFIFO_SIZE;
265 max_gfsize = GFIFO_SIZE;
266 while (1)
267 {
268 if (ainfo->vid_en)
269 {
270 if (ainfo->wcvocc > ainfo->vocc) ainfo->wcvocc = ainfo->vocc;
271 if (ainfo->wcvlwm > vlwm) ainfo->wcvlwm = vlwm ;
272 ns = 1000000 * ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
273 vfsize = ns * ainfo->vdrain_rate / 1000000;
274 vfsize = ainfo->wcvlwm - ainfo->vburst_size + vfsize;
275 }
276 if (state->enable_mp)
277 {
278 if (ainfo->wcmocc > ainfo->mocc) ainfo->wcmocc = ainfo->mocc;
279 }
280 if (ainfo->gr_en)
281 {
282 if (ainfo->wcglwm > glwm) ainfo->wcglwm = glwm ;
283 if (ainfo->wcgocc > ainfo->gocc) ainfo->wcgocc = ainfo->gocc;
284 ns = 1000000 * (ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
285 gfsize = (ns * (long) ainfo->gdrain_rate)/1000000;
286 gfsize = ainfo->wcglwm - ainfo->gburst_size + gfsize;
287 }
288 mfsize = 0;
289 if (!state->gr_during_vid && ainfo->vid_en)
290 if (ainfo->vid_en && (ainfo->vocc < 0) && !ainfo->vid_only_once)
291 next = VIDEO;
292 else if (ainfo->mocc < 0)
293 next = MPORT;
294 else if (ainfo->gocc< ainfo->by_gfacc)
295 next = GRAPHICS;
296 else return (0);
297 else switch (ainfo->priority)
298 {
299 case VIDEO:
300 if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
301 next = VIDEO;
302 else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
303 next = GRAPHICS;
304 else if (ainfo->mocc<0)
305 next = MPORT;
306 else return (0);
307 break;
308 case GRAPHICS:
309 if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
310 next = GRAPHICS;
311 else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
312 next = VIDEO;
313 else if (ainfo->mocc<0)
314 next = MPORT;
315 else return (0);
316 break;
317 default:
318 if (ainfo->mocc<0)
319 next = MPORT;
320 else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
321 next = GRAPHICS;
322 else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
323 next = VIDEO;
324 else return (0);
325 break;
326 }
327 last = cur;
328 cur = next;
329 iter++;
330 switch (cur)
331 {
332 case VIDEO:
333 if (last==cur) misses = 0;
334 else if (ainfo->first_vacc) misses = vmisses;
335 else misses = 1;
336 ainfo->first_vacc = 0;
337 if (last!=cur)
338 {
339 ns = 1000000 * (vmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
340 vlwm = ns * ainfo->vdrain_rate/ 1000000;
341 vlwm = ainfo->vocc - vlwm;
342 }
343 ns = 1000000*(misses*state->mem_page_miss + ainfo->vburst_size)/(state->memory_width/8)/state->mclk_khz;
344 ainfo->vocc = ainfo->vocc + ainfo->vburst_size - ns*ainfo->vdrain_rate/1000000;
345 ainfo->gocc = ainfo->gocc - ns*ainfo->gdrain_rate/1000000;
346 ainfo->mocc = ainfo->mocc - ns*ainfo->mdrain_rate/1000000;
347 break;
348 case GRAPHICS:
349 if (last==cur) misses = 0;
350 else if (ainfo->first_gacc) misses = gmisses;
351 else misses = 1;
352 ainfo->first_gacc = 0;
353 if (last!=cur)
354 {
355 ns = 1000000*(gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz ;
356 glwm = ns * ainfo->gdrain_rate/1000000;
357 glwm = ainfo->gocc - glwm;
358 }
359 ns = 1000000*(misses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
360 ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
361 ainfo->gocc = ainfo->gocc + ainfo->gburst_size - ns*ainfo->gdrain_rate/1000000;
362 ainfo->mocc = ainfo->mocc + 0 - ns*ainfo->mdrain_rate/1000000;
363 break;
364 default:
365 if (last==cur) misses = 0;
366 else if (ainfo->first_macc) misses = mmisses;
367 else misses = 1;
368 ainfo->first_macc = 0;
369 ns = 1000000*(misses*state->mem_page_miss + mburst_size/(state->memory_width/8))/state->mclk_khz;
370 ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
371 ainfo->gocc = ainfo->gocc + 0 - ns*ainfo->gdrain_rate/1000000;
372 ainfo->mocc = ainfo->mocc + mburst_size - ns*ainfo->mdrain_rate/1000000;
373 break;
374 }
375 if (iter>100)
376 {
377 ainfo->converged = 0;
378 return (1);
379 }
380 ns = 1000000*ainfo->gburst_size/(state->memory_width/8)/state->mclk_khz;
381 tmp = ns * ainfo->gdrain_rate/1000000;
382 if (abs(ainfo->gburst_size) + ((abs(ainfo->wcglwm) + 16 ) & ~0x7) - tmp > max_gfsize)
383 {
384 ainfo->converged = 0;
385 return (1);
386 }
387 ns = 1000000*ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
388 tmp = ns * ainfo->vdrain_rate/1000000;
389 if (abs(ainfo->vburst_size) + (abs(ainfo->wcvlwm + 32) & ~0xf) - tmp> VFIFO_SIZE)
390 {
391 ainfo->converged = 0;
392 return (1);
393 }
394 if (abs(ainfo->gocc) > max_gfsize)
395 {
396 ainfo->converged = 0;
397 return (1);
398 }
399 if (abs(ainfo->vocc) > VFIFO_SIZE)
400 {
401 ainfo->converged = 0;
402 return (1);
403 }
404 if (abs(ainfo->mocc) > MFIFO_SIZE)
405 {
406 ainfo->converged = 0;
407 return (1);
408 }
409 if (abs(vfsize) > VFIFO_SIZE)
410 {
411 ainfo->converged = 0;
412 return (1);
413 }
414 if (abs(gfsize) > max_gfsize)
415 {
416 ainfo->converged = 0;
417 return (1);
418 }
419 if (abs(mfsize) > MFIFO_SIZE)
420 {
421 ainfo->converged = 0;
422 return (1);
423 }
424 }
425 }
426 static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
427 {
428 long ens, vns, mns, gns;
429 int mmisses, gmisses, vmisses, eburst_size, mburst_size;
430 int refresh_cycle;
431
432 refresh_cycle = 2*(state->mclk_khz/state->pclk_khz) + 5;
433 mmisses = 2;
434 if (state->mem_aligned) gmisses = 2;
435 else gmisses = 3;
436 vmisses = 2;
437 eburst_size = state->memory_width * 1;
438 mburst_size = 32;
> 439 if (!state->mclk_khz)
440 return (0);
441
442 gns = 1000000 * (gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
443 ainfo->by_gfacc = gns*ainfo->gdrain_rate/1000000;
444 ainfo->wcmocc = 0;
445 ainfo->wcgocc = 0;
446 ainfo->wcvocc = 0;
447 ainfo->wcvlwm = 0;
448 ainfo->wcglwm = 0;
449 ainfo->engine_en = 1;
450 ainfo->converged = 1;
451 if (ainfo->engine_en)
452 {
453 ens = 1000000*(state->mem_page_miss + eburst_size/(state->memory_width/8) +refresh_cycle)/state->mclk_khz;
454 ainfo->mocc = state->enable_mp ? 0-ens*ainfo->mdrain_rate/1000000 : 0;
455 ainfo->vocc = ainfo->vid_en ? 0-ens*ainfo->vdrain_rate/1000000 : 0;
456 ainfo->gocc = ainfo->gr_en ? 0-ens*ainfo->gdrain_rate/1000000 : 0;
457 ainfo->cur = ENGINE;
458 ainfo->first_vacc = 1;
459 ainfo->first_gacc = 1;
460 ainfo->first_macc = 1;
461 nv3_iterate(res_info, state,ainfo);
462 }
463 if (state->enable_mp)
464 {
465 mns = 1000000 * (mmisses*state->mem_page_miss + mburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
466 ainfo->mocc = state->enable_mp ? 0 : mburst_size - mns*ainfo->mdrain_rate/1000000;
467 ainfo->vocc = ainfo->vid_en ? 0 : 0- mns*ainfo->vdrain_rate/1000000;
468 ainfo->gocc = ainfo->gr_en ? 0: 0- mns*ainfo->gdrain_rate/1000000;
469 ainfo->cur = MPORT;
470 ainfo->first_vacc = 1;
471 ainfo->first_gacc = 1;
472 ainfo->first_macc = 0;
473 nv3_iterate(res_info, state,ainfo);
474 }
475 if (ainfo->gr_en)
476 {
477 ainfo->first_vacc = 1;
478 ainfo->first_gacc = 0;
479 ainfo->first_macc = 1;
480 gns = 1000000*(gmisses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
481 ainfo->gocc = ainfo->gburst_size - gns*ainfo->gdrain_rate/1000000;
482 ainfo->vocc = ainfo->vid_en? 0-gns*ainfo->vdrain_rate/1000000 : 0;
483 ainfo->mocc = state->enable_mp ? 0-gns*ainfo->mdrain_rate/1000000: 0;
484 ainfo->cur = GRAPHICS;
485 nv3_iterate(res_info, state,ainfo);
486 }
487 if (ainfo->vid_en)
488 {
489 ainfo->first_vacc = 0;
490 ainfo->first_gacc = 1;
491 ainfo->first_macc = 1;
492 vns = 1000000*(vmisses*state->mem_page_miss + ainfo->vburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
493 ainfo->vocc = ainfo->vburst_size - vns*ainfo->vdrain_rate/1000000;
494 ainfo->gocc = ainfo->gr_en? (0-vns*ainfo->gdrain_rate/1000000) : 0;
495 ainfo->mocc = state->enable_mp? 0-vns*ainfo->mdrain_rate/1000000 :0 ;
496 ainfo->cur = VIDEO;
497 nv3_iterate(res_info, state, ainfo);
498 }
499 if (ainfo->converged)
500 {
501 res_info->graphics_lwm = (int)abs(ainfo->wcglwm) + 16;
502 res_info->video_lwm = (int)abs(ainfo->wcvlwm) + 32;
503 res_info->graphics_burst_size = ainfo->gburst_size;
504 res_info->video_burst_size = ainfo->vburst_size;
505 res_info->graphics_hi_priority = (ainfo->priority == GRAPHICS);
506 res_info->media_hi_priority = (ainfo->priority == MPORT);
507 if (res_info->video_lwm > 160)
508 {
509 res_info->graphics_lwm = 256;
510 res_info->video_lwm = 128;
511 res_info->graphics_burst_size = 64;
512 res_info->video_burst_size = 64;
513 res_info->graphics_hi_priority = 0;
514 res_info->media_hi_priority = 0;
515 ainfo->converged = 0;
516 return (0);
517 }
518 if (res_info->video_lwm > 128)
519 {
520 res_info->video_lwm = 128;
521 }
522 return (1);
523 }
524 else
525 {
526 res_info->graphics_lwm = 256;
527 res_info->video_lwm = 128;
528 res_info->graphics_burst_size = 64;
529 res_info->video_burst_size = 64;
530 res_info->graphics_hi_priority = 0;
531 res_info->media_hi_priority = 0;
532 return (0);
533 }
534 }
535 static char nv3_get_param(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
536 {
537 int done, g,v, p;
538
539 done = 0;
540 for (p=0; p < 2; p++)
541 {
542 for (g=128 ; g > 32; g= g>> 1)
543 {
544 for (v=128; v >=32; v = v>> 1)
545 {
546 ainfo->priority = p;
547 ainfo->gburst_size = g;
548 ainfo->vburst_size = v;
549 done = nv3_arb(res_info, state,ainfo);
550 if (done && (g==128))
551 if ((res_info->graphics_lwm + g) > 256)
552 done = 0;
553 if (done)
554 goto Done;
555 }
556 }
557 }
558
559 Done:
560 return done;
561 }
562 static void nv3CalcArbitration
563 (
564 nv3_fifo_info * res_info,
565 nv3_sim_state * state
566 )
567 {
568 nv3_fifo_info save_info;
569 nv3_arb_info ainfo;
570 char res_gr, res_vid;
571
572 ainfo.gr_en = 1;
573 ainfo.vid_en = state->enable_video;
574 ainfo.vid_only_once = 0;
575 ainfo.gr_only_once = 0;
576 ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8);
577 ainfo.vdrain_rate = (int) state->pclk_khz * 2;
578 if (state->video_scale != 0)
579 ainfo.vdrain_rate = ainfo.vdrain_rate/state->video_scale;
580 ainfo.mdrain_rate = 33000;
581 res_info->rtl_values = 0;
582 if (!state->gr_during_vid && state->enable_video)
583 {
584 ainfo.gr_only_once = 1;
585 ainfo.gr_en = 1;
586 ainfo.gdrain_rate = 0;
587 res_vid = nv3_get_param(res_info, state, &ainfo);
588 res_vid = ainfo.converged;
589 save_info.video_lwm = res_info->video_lwm;
590 save_info.video_burst_size = res_info->video_burst_size;
591 ainfo.vid_en = 1;
592 ainfo.vid_only_once = 1;
593 ainfo.gr_en = 1;
594 ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8);
595 ainfo.vdrain_rate = 0;
596 res_gr = nv3_get_param(res_info, state, &ainfo);
597 res_gr = ainfo.converged;
598 res_info->video_lwm = save_info.video_lwm;
599 res_info->video_burst_size = save_info.video_burst_size;
600 res_info->valid = res_gr & res_vid;
601 }
602 else
603 {
604 if (!ainfo.gr_en) ainfo.gdrain_rate = 0;
605 if (!ainfo.vid_en) ainfo.vdrain_rate = 0;
606 res_gr = nv3_get_param(res_info, state, &ainfo);
607 res_info->valid = ainfo.converged;
608 }
609 }
610 static void nv3UpdateArbitrationSettings
611 (
612 unsigned VClk,
613 unsigned pixelDepth,
614 unsigned *burst,
615 unsigned *lwm,
616 RIVA_HW_INST *chip
617 )
618 {
619 nv3_fifo_info fifo_data;
620 nv3_sim_state sim_data;
621 unsigned int M, N, P, pll, MClk;
622
623 pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0);
624 M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
625 MClk = (N * chip->CrystalFreqKHz / M) >> P;
626 sim_data.pix_bpp = (char)pixelDepth;
627 sim_data.enable_video = 0;
628 sim_data.enable_mp = 0;
629 sim_data.video_scale = 1;
630 sim_data.memory_width = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ?
631 128 : 64;
632 sim_data.memory_width = 128;
633
634 sim_data.mem_latency = 9;
635 sim_data.mem_aligned = 1;
636 sim_data.mem_page_miss = 11;
637 sim_data.gr_during_vid = 0;
638 sim_data.pclk_khz = VClk;
639 sim_data.mclk_khz = MClk;
640 nv3CalcArbitration(&fifo_data, &sim_data);
641 if (fifo_data.valid)
642 {
643 int b = fifo_data.graphics_burst_size >> 4;
644 *burst = 0;
645 while (b >>= 1)
646 (*burst)++;
647 *lwm = fifo_data.graphics_lwm >> 3;
648 }
649 else
650 {
651 *lwm = 0x24;
652 *burst = 0x2;
653 }
654 }
655 static void nv4CalcArbitration
656 (
657 nv4_fifo_info *fifo,
658 nv4_sim_state *arb
659 )
660 {
661 int data, pagemiss, cas,width, video_enable, bpp;
662 int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
663 int found, mclk_extra, mclk_loop, cbs, m1, p1;
664 int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
665 int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
666 int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt,clwm;
667
668 fifo->valid = 1;
669 pclk_freq = arb->pclk_khz;
670 mclk_freq = arb->mclk_khz;
671 nvclk_freq = arb->nvclk_khz;
672 pagemiss = arb->mem_page_miss;
673 cas = arb->mem_latency;
674 width = arb->memory_width >> 6;
675 video_enable = arb->enable_video;
676 bpp = arb->pix_bpp;
677 mp_enable = arb->enable_mp;
678 clwm = 0;
679 vlwm = 0;
680 cbs = 128;
681 pclks = 2;
682 nvclks = 2;
683 nvclks += 2;
684 nvclks += 1;
685 mclks = 5;
686 mclks += 3;
687 mclks += 1;
688 mclks += cas;
689 mclks += 1;
690 mclks += 1;
691 mclks += 1;
692 mclks += 1;
693 mclk_extra = 3;
694 nvclks += 2;
695 nvclks += 1;
696 nvclks += 1;
697 nvclks += 1;
698 if (mp_enable)
699 mclks+=4;
700 nvclks += 0;
701 pclks += 0;
702 found = 0;
703 vbs = 0;
704 while (found != 1)
705 {
706 fifo->valid = 1;
707 found = 1;
708 mclk_loop = mclks+mclk_extra;
709 us_m = mclk_loop *1000*1000 / mclk_freq;
710 us_n = nvclks*1000*1000 / nvclk_freq;
711 us_p = nvclks*1000*1000 / pclk_freq;
712 if (video_enable)
713 {
714 video_drain_rate = pclk_freq * 2;
715 crtc_drain_rate = pclk_freq * bpp/8;
716 vpagemiss = 2;
717 vpagemiss += 1;
718 crtpagemiss = 2;
719 vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
720 if (nvclk_freq * 2 > mclk_freq * width)
721 video_fill_us = cbs*1000*1000 / 16 / nvclk_freq ;
722 else
723 video_fill_us = cbs*1000*1000 / (8 * width) / mclk_freq;
724 us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
725 vlwm = us_video * video_drain_rate/(1000*1000);
726 vlwm++;
727 vbs = 128;
728 if (vlwm > 128) vbs = 64;
729 if (vlwm > (256-64)) vbs = 32;
730 if (nvclk_freq * 2 > mclk_freq * width)
731 video_fill_us = vbs *1000*1000/ 16 / nvclk_freq ;
732 else
733 video_fill_us = vbs*1000*1000 / (8 * width) / mclk_freq;
734 cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq;
735 us_crt =
736 us_video
737 +video_fill_us
738 +cpm_us
739 +us_m + us_n +us_p
740 ;
741 clwm = us_crt * crtc_drain_rate/(1000*1000);
742 clwm++;
743 }
744 else
745 {
746 crtc_drain_rate = pclk_freq * bpp/8;
747 crtpagemiss = 2;
748 crtpagemiss += 1;
749 cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq;
750 us_crt = cpm_us + us_m + us_n + us_p ;
751 clwm = us_crt * crtc_drain_rate/(1000*1000);
752 clwm++;
753 }
754 m1 = clwm + cbs - 512;
755 p1 = m1 * pclk_freq / mclk_freq;
756 p1 = p1 * bpp / 8;
757 if ((p1 < m1) && (m1 > 0))
758 {
759 fifo->valid = 0;
760 found = 0;
761 if (mclk_extra ==0) found = 1;
762 mclk_extra--;
763 }
764 else if (video_enable)
765 {
766 if ((clwm > 511) || (vlwm > 255))
767 {
768 fifo->valid = 0;
769 found = 0;
770 if (mclk_extra ==0) found = 1;
771 mclk_extra--;
772 }
773 }
774 else
775 {
776 if (clwm > 519)
777 {
778 fifo->valid = 0;
779 found = 0;
780 if (mclk_extra ==0) found = 1;
781 mclk_extra--;
782 }
783 }
784 if (clwm < 384) clwm = 384;
785 if (vlwm < 128) vlwm = 128;
786 data = (int)(clwm);
787 fifo->graphics_lwm = data;
788 fifo->graphics_burst_size = 128;
789 data = (int)((vlwm+15));
790 fifo->video_lwm = data;
791 fifo->video_burst_size = vbs;
792 }
793 }
794 static void nv4UpdateArbitrationSettings
795 (
796 unsigned VClk,
797 unsigned pixelDepth,
798 unsigned *burst,
799 unsigned *lwm,
800 RIVA_HW_INST *chip
801 )
802 {
803 nv4_fifo_info fifo_data;
804 nv4_sim_state sim_data;
805 unsigned int M, N, P, pll, MClk, NVClk, cfg1;
806
807 pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0);
808 M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
809 MClk = (N * chip->CrystalFreqKHz / M) >> P;
810 pll = NV_RD32(&chip->PRAMDAC0[0x00000500/4], 0);
811 M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
812 NVClk = (N * chip->CrystalFreqKHz / M) >> P;
813 cfg1 = NV_RD32(&chip->PFB[0x00000204/4], 0);
814 sim_data.pix_bpp = (char)pixelDepth;
815 sim_data.enable_video = 0;
816 sim_data.enable_mp = 0;
817 sim_data.memory_width = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ?
818 128 : 64;
819 sim_data.mem_latency = (char)cfg1 & 0x0F;
820 sim_data.mem_aligned = 1;
821 sim_data.mem_page_miss = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01));
822 sim_data.gr_during_vid = 0;
823 sim_data.pclk_khz = VClk;
824 sim_data.mclk_khz = MClk;
825 sim_data.nvclk_khz = NVClk;
826 nv4CalcArbitration(&fifo_data, &sim_data);
827 if (fifo_data.valid)
828 {
829 int b = fifo_data.graphics_burst_size >> 4;
830 *burst = 0;
831 while (b >>= 1)
832 (*burst)++;
833 *lwm = fifo_data.graphics_lwm >> 3;
834 }
835 }
836 static void nv10CalcArbitration
837 (
838 nv10_fifo_info *fifo,
839 nv10_sim_state *arb
840 )
841 {
842 int data, pagemiss, width, video_enable, bpp;
843 int nvclks, mclks, pclks, vpagemiss, crtpagemiss;
844 int nvclk_fill;
845 int found, mclk_extra, mclk_loop, cbs, m1;
846 int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
847 int us_m, us_m_min, us_n, us_p, crtc_drain_rate;
848 int vus_m;
849 int vpm_us, us_video, cpm_us, us_crt,clwm;
850 int clwm_rnd_down;
851 int m2us, us_pipe_min, p1clk, p2;
852 int min_mclk_extra;
853 int us_min_mclk_extra;
854
855 fifo->valid = 1;
856 pclk_freq = arb->pclk_khz; /* freq in KHz */
857 mclk_freq = arb->mclk_khz;
858 nvclk_freq = arb->nvclk_khz;
859 pagemiss = arb->mem_page_miss;
860 width = arb->memory_width/64;
861 video_enable = arb->enable_video;
862 bpp = arb->pix_bpp;
863 mp_enable = arb->enable_mp;
864 clwm = 0;
865
866 cbs = 512;
867
868 pclks = 4; /* lwm detect. */
869
870 nvclks = 3; /* lwm -> sync. */
871 nvclks += 2; /* fbi bus cycles (1 req + 1 busy) */
872
873 mclks = 1; /* 2 edge sync. may be very close to edge so just put one. */
874
875 mclks += 1; /* arb_hp_req */
876 mclks += 5; /* ap_hp_req tiling pipeline */
877
878 mclks += 2; /* tc_req latency fifo */
879 mclks += 2; /* fb_cas_n_ memory request to fbio block */
880 mclks += 7; /* sm_d_rdv data returned from fbio block */
881
882 /* fb.rd.d.Put_gc need to accumulate 256 bits for read */
883 if (arb->memory_type == 0)
884 if (arb->memory_width == 64) /* 64 bit bus */
885 mclks += 4;
886 else
887 mclks += 2;
888 else
889 if (arb->memory_width == 64) /* 64 bit bus */
890 mclks += 2;
891 else
892 mclks += 1;
893
894 if ((!video_enable) && (arb->memory_width == 128))
895 {
896 mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */
897 min_mclk_extra = 17;
898 }
899 else
900 {
901 mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */
902 /* mclk_extra = 4; */ /* Margin of error */
903 min_mclk_extra = 18;
904 }
905
906 nvclks += 1; /* 2 edge sync. may be very close to edge so just put one. */
907 nvclks += 1; /* fbi_d_rdv_n */
908 nvclks += 1; /* Fbi_d_rdata */
909 nvclks += 1; /* crtfifo load */
910
911 if(mp_enable)
912 mclks+=4; /* Mp can get in with a burst of 8. */
913 /* Extra clocks determined by heuristics */
914
915 nvclks += 0;
916 pclks += 0;
917 found = 0;
918 while(found != 1) {
919 fifo->valid = 1;
920 found = 1;
921 mclk_loop = mclks+mclk_extra;
922 us_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */
923 us_m_min = mclks * 1000*1000 / mclk_freq; /* Minimum Mclk latency in us */
924 us_min_mclk_extra = min_mclk_extra *1000*1000 / mclk_freq;
925 us_n = nvclks*1000*1000 / nvclk_freq;/* nvclk latency in us */
926 us_p = pclks*1000*1000 / pclk_freq;/* nvclk latency in us */
927 us_pipe_min = us_m_min + us_n + us_p;
928
929 vus_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */
930
931 if(video_enable) {
932 crtc_drain_rate = pclk_freq * bpp/8; /* MB/s */
933
934 vpagemiss = 1; /* self generating page miss */
935 vpagemiss += 1; /* One higher priority before */
936
937 crtpagemiss = 2; /* self generating page miss */
938 if(mp_enable)
939 crtpagemiss += 1; /* if MA0 conflict */
940
941 vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
942
943 us_video = vpm_us + vus_m; /* Video has separate read return path */
944
945 cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq;
946 us_crt =
947 us_video /* Wait for video */
948 +cpm_us /* CRT Page miss */
949 +us_m + us_n +us_p /* other latency */
950 ;
951
952 clwm = us_crt * crtc_drain_rate/(1000*1000);
953 clwm++; /* fixed point <= float_point - 1. Fixes that */
954 } else {
955 crtc_drain_rate = pclk_freq * bpp/8; /* bpp * pclk/8 */
956
957 crtpagemiss = 1; /* self generating page miss */
958 crtpagemiss += 1; /* MA0 page miss */
959 if(mp_enable)
960 crtpagemiss += 1; /* if MA0 conflict */
961 cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq;
962 us_crt = cpm_us + us_m + us_n + us_p ;
963 clwm = us_crt * crtc_drain_rate/(1000*1000);
964 clwm++; /* fixed point <= float_point - 1. Fixes that */
965
966 /*
967 //
968 // Another concern, only for high pclks so don't do this
969 // with video:
970 // What happens if the latency to fetch the cbs is so large that
971 // fifo empties. In that case we need to have an alternate clwm value
972 // based off the total burst fetch
973 //
974 us_crt = (cbs * 1000 * 1000)/ (8*width)/mclk_freq ;
975 us_crt = us_crt + us_m + us_n + us_p + (4 * 1000 * 1000)/mclk_freq;
976 clwm_mt = us_crt * crtc_drain_rate/(1000*1000);
977 clwm_mt ++;
978 if(clwm_mt > clwm)
979 clwm = clwm_mt;
980 */
981 /* Finally, a heuristic check when width == 64 bits */
982 if(width == 1){
983 nvclk_fill = nvclk_freq * 8;
984 if(crtc_drain_rate * 100 >= nvclk_fill * 102)
985 clwm = 0xfff; /*Large number to fail */
986
987 else if(crtc_drain_rate * 100 >= nvclk_fill * 98) {
988 clwm = 1024;
989 cbs = 512;
990 }
991 }
992 }
993
994
995 /*
996 Overfill check:
997
998 */
999
1000 clwm_rnd_down = ((int)clwm/8)*8;
1001 if (clwm_rnd_down < clwm)
1002 clwm += 8;
1003
1004 m1 = clwm + cbs - 1024; /* Amount of overfill */
1005 m2us = us_pipe_min + us_min_mclk_extra;
1006
1007 /* pclk cycles to drain */
1008 p1clk = m2us * pclk_freq/(1000*1000);
1009 p2 = p1clk * bpp / 8; /* bytes drained. */
1010
1011 if((p2 < m1) && (m1 > 0)) {
1012 fifo->valid = 0;
1013 found = 0;
1014 if(min_mclk_extra == 0) {
1015 if(cbs <= 32) {
1016 found = 1; /* Can't adjust anymore! */
1017 } else {
1018 cbs = cbs/2; /* reduce the burst size */
1019 }
1020 } else {
1021 min_mclk_extra--;
1022 }
1023 } else {
1024 if (clwm > 1023){ /* Have some margin */
1025 fifo->valid = 0;
1026 found = 0;
1027 if(min_mclk_extra == 0)
1028 found = 1; /* Can't adjust anymore! */
1029 else
1030 min_mclk_extra--;
1031 }
1032 }
1033
1034 if(clwm < (1024-cbs+8)) clwm = 1024-cbs+8;
1035 data = (int)(clwm);
1036 /* printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n", clwm, data ); */
1037 fifo->graphics_lwm = data; fifo->graphics_burst_size = cbs;
1038
1039 /* printf("VID LWM: %f bytes, prog: 0x%x, bs: %d\n, ", vlwm, data, vbs ); */
1040 fifo->video_lwm = 1024; fifo->video_burst_size = 512;
1041 }
1042 }
1043 static void nv10UpdateArbitrationSettings
1044 (
1045 unsigned VClk,
1046 unsigned pixelDepth,
1047 unsigned *burst,
1048 unsigned *lwm,
1049 RIVA_HW_INST *chip
1050 )
1051 {
1052 nv10_fifo_info fifo_data;
1053 nv10_sim_state sim_data;
1054 unsigned int M, N, P, pll, MClk, NVClk, cfg1;
1055
1056 pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0);
1057 M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
1058 MClk = (N * chip->CrystalFreqKHz / M) >> P;
1059 pll = NV_RD32(&chip->PRAMDAC0[0x00000500/4], 0);
1060 M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
1061 NVClk = (N * chip->CrystalFreqKHz / M) >> P;
1062 cfg1 = NV_RD32(&chip->PFB[0x00000204/4], 0);
1063 sim_data.pix_bpp = (char)pixelDepth;
1064 sim_data.enable_video = 0;
1065 sim_data.enable_mp = 0;
1066 sim_data.memory_type = (NV_RD32(&chip->PFB[0x00000200/4], 0) & 0x01) ?
1067 1 : 0;
1068 sim_data.memory_width = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ?
1069 128 : 64;
1070 sim_data.mem_latency = (char)cfg1 & 0x0F;
1071 sim_data.mem_aligned = 1;
1072 sim_data.mem_page_miss = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01));
1073 sim_data.gr_during_vid = 0;
1074 sim_data.pclk_khz = VClk;
1075 sim_data.mclk_khz = MClk;
1076 sim_data.nvclk_khz = NVClk;
1077 nv10CalcArbitration(&fifo_data, &sim_data);
1078 if (fifo_data.valid)
1079 {
1080 int b = fifo_data.graphics_burst_size >> 4;
1081 *burst = 0;
1082 while (b >>= 1)
1083 (*burst)++;
1084 *lwm = fifo_data.graphics_lwm >> 3;
1085 }
1086 }
1087
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v2 14/19] video/vga: Add VGA_IS0_R
From: Jani Nikula @ 2025-12-09 10:55 UTC (permalink / raw)
To: Ville Syrjala, intel-gfx; +Cc: intel-xe, Helge Deller, linux-fbdev, dri-devel
In-Reply-To: <20251209075549.14051-1-ville.syrjala@linux.intel.com>
On Tue, 09 Dec 2025, Ville Syrjala <ville.syrjala@linux.intel.com> wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Add a proper name for the "Input status register 0" IO address.
> Currently we have some code that does read addressed using the
> aliasing VGA_MSR_W define, making it unclear what register we're
> actually reading.
>
> v2: Remove stray '?'
>
> Cc: Helge Deller <deller@gmx.de>
> Cc: linux-fbdev@vger.kernel.org
> Cc: dri-devel@lists.freedesktop.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
> ---
> include/video/vga.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/video/vga.h b/include/video/vga.h
> index 468764d6727a..2f13c371800b 100644
> --- a/include/video/vga.h
> +++ b/include/video/vga.h
> @@ -46,6 +46,7 @@
> #define VGA_MIS_R 0x3CC /* Misc Output Read Register */
> #define VGA_MIS_W 0x3C2 /* Misc Output Write Register */
> #define VGA_FTC_R 0x3CA /* Feature Control Read Register */
> +#define VGA_IS0_R 0x3C2 /* Input Status Register 0 */
> #define VGA_IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
> #define VGA_IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
> #define VGA_PEL_D 0x3C9 /* PEL Data Register */
--
Jani Nikula, Intel
^ permalink raw reply
* Re: [PATCH 0/3] fbdev: Guard sysfs interfaces under CONFIG_FB_DEVICE
From: Andy Shevchenko @ 2025-12-09 14:25 UTC (permalink / raw)
To: Helge Deller
Cc: Thomas Zimmermann, Chintan Patel, linux-fbdev, linux-staging,
linux-omap, linux-kernel, dri-devel, andy, gregkh
In-Reply-To: <f5d50007-5b48-47cb-8133-72fca274d562@gmx.de>
On Tue, Dec 9, 2025 at 10:23 AM Helge Deller <deller@gmx.de> wrote:
> On 12/9/25 08:27, Thomas Zimmermann wrote:
...
> This whole series adds a whole lot of ifdef'ery, which I think is the
> worst approach. It makes the code less readable and leads to two code
> paths, which may trigger different build errors depending on the config.
>
> I'm sure it must be possible to do the same without adding more #ifdefs,
> e.g. by introducing a function like dev_of_fbinfo(fbinfo) which
> simply returns NULL for the FB_DEVICE=n case. Then, that value can be tested
> like
> if (dev_of_fbinfo(fbinfo))
> {...do-the-things...}
> For the FB_DEVICE=n case this will then be optimized out by the compiler,
> while you still have full compiler syntax checking.
>
> Thoughts?
I second you. I am also not a fan of ifdeffery when it can be avoided.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v6 1/4] dt-bindings: backlight: Add max25014 support
From: Rob Herring @ 2025-12-09 19:07 UTC (permalink / raw)
To: Maud Spierings
Cc: Frank Li, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Liam Girdwood, Mark Brown, dri-devel, linux-leds, devicetree,
linux-kernel, linux-fbdev, imx, linux-arm-kernel
In-Reply-To: <e428c3a9-49e2-4af5-b597-2cdfef7028f5@gocontroll.com>
On Mon, Dec 08, 2025 at 02:56:50PM +0100, Maud Spierings wrote:
> On 12/2/25 15:53, Frank Li wrote:
> > On Tue, Dec 02, 2025 at 08:46:21AM +0100, Maud Spierings wrote:
> > > On 12/1/25 17:52, Frank Li wrote:
> > > > On Mon, Dec 01, 2025 at 12:53:20PM +0100, Maud Spierings via B4 Relay wrote:
> > > > > From: Maud Spierings <maudspierings@gocontroll.com>
> > > > >
> > > > > The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> > > > > with integrated boost controller.
> > > > >
> > > > > Signed-off-by: Maud Spierings <maudspierings@gocontroll.com>
> > > > >
> > > > > ---
> > > > >
> > > > > In the current implementation the control registers for channel 1,
> > > > > control all channels. So only one led subnode with led-sources is
> > > > > supported right now. If at some point the driver functionality is
> > > > > expanded the bindings can be easily extended with it.
> > > > > ---
> > > > > .../bindings/leds/backlight/maxim,max25014.yaml | 107 +++++++++++++++++++++
> > > > > MAINTAINERS | 5 +
> > > > > 2 files changed, 112 insertions(+)
> > > > >
> > > > > diff --git a/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> > > > > new file mode 100644
> > > > > index 000000000000..e83723224b07
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/leds/backlight/maxim,max25014.yaml
> > > > > @@ -0,0 +1,107 @@
> > > > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > > > > +%YAML 1.2
> > > > > +---
> > > > > +$id: http://devicetree.org/schemas/leds/backlight/maxim,max25014.yaml#
> > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > +
> > > > > +title: Maxim max25014 backlight controller
> > > > > +
> > > > > +maintainers:
> > > > > + - Maud Spierings <maudspierings@gocontroll.com>
> > > > > +
> > > > > +properties:
> > > > > + compatible:
> > > > > + enum:
> > > > > + - maxim,max25014
> > > > > +
> > > > > + reg:
> > > > > + maxItems: 1
> > > > > +
> > > > > + "#address-cells":
> > > > > + const: 1
> > > > > +
> > > > > + "#size-cells":
> > > > > + const: 0
> > > > > +
> > > > > + enable-gpios:
> > > > > + maxItems: 1
> > > > > +
> > > > > + interrupts:
> > > > > + maxItems: 1
> > > > > +
> > > > > + power-supply:
> > > > > + description: Regulator which controls the boost converter input rail.
> > > > > +
> > > > > + pwms:
> > > > > + maxItems: 1
> > > > > +
> > > > > + maxim,iset:
> > > > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > > > + maximum: 15
> > > > > + default: 11
> > > > > + description:
> > > > > + Value of the ISET field in the ISET register. This controls the current
> > > > > + scale of the outputs, a higher number means more current.
> > > > > +
> > > > > + led@0:
> > > >
> > > > define whole binding, allow 0-3. binding is not related with driver's
> > > > implement.
> > > >
> > > > it'd better put unders leds.
> > > >
> > >
> > > so like:
> > >
> > > backlight: backlight@6f {
> > > compatible = "maxim,max25014";
> > > reg = <0x6f>;
> > > enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
> > > pinctrl-names = "default";
> > > pinctrl-0 = <&pinctrl_backlight>;
> > > maxim,iset = <7>;
> > >
> > > leds {
> > > #address-cells = <1>;
> > > #size-cells = <0>;
> > >
> > > led@0 {
> > > reg = <0>;
> > > led-sources = <0 1 2>;
> > > default-brightness = <50>;
> > > };
> > >
> > > optional led@#....
> > > };
> > > };
> > >
> > > right?
> >
> > yes.
> >
>
> I am feeling a bit weird about these led sub nodes, because it is not
> programmed as a led driver, it is programmed as a backlight. I am trying to
> figure out how this would be used later when the led strings are
> individually controllable.
>
> it isn't possible to link the seperate strings to different displays because
> it is only one backlight device, so I don't seen any reason why it would
> ever be used in another way than what it is now, were all strings are
> programmed by one register.
>
> The only way I can make sense of it is if instead I program this device as a
> led driver and then use the led_bl driver as the actual backlight.
>
> Thats a pretty big step in a different direction, but then the led subnodes
> at least can be properly used I feel.
If you don't have any use for anything other than driving a single
backlight, then I'd just drop the led nodes completely.
Rob
^ permalink raw reply
* Re: [PATCH 1/3] fbtft: Make sysfs and dev_*() logging conditional on FB_DEVICE
From: Chintan Patel @ 2025-12-10 4:24 UTC (permalink / raw)
To: Thomas Zimmermann, linux-fbdev, linux-staging, linux-omap
Cc: linux-kernel, dri-devel, andy, deller, gregkh
In-Reply-To: <329423e8-d778-4f30-904a-825b1be72ce2@suse.de>
Hi Thomas,
On 12/8/25 23:25, Thomas Zimmermann wrote:
> Hi
>
> Am 09.12.25 um 05:27 schrieb Chintan Patel:
>> The fbtft core and sysfs implementation unconditionally dereference
>> fb_info->dev and register sysfs attributes. When FB_DEVICE=n, these
>> fields are unavailable, leading to build failures.
>>
>> This patch wraps all sysfs attribute creation/removal and dev_dbg/
>> dev_info
>> logging in #ifdef CONFIG_FB_DEVICE, with pr_*() fallbacks for the
>> non-FB_DEVICE case. This makes fbtft fully buildable when FB_DEVICE is
>> disabled.
>>
>> Signed-off-by: Chintan Patel <chintanlike@gmail.com>
>> ---
>> drivers/staging/fbtft/fbtft-core.c | 20 ++++++++++++++++++--
>> drivers/staging/fbtft/fbtft-sysfs.c | 8 ++++++++
>> 2 files changed, 26 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/
>> fbtft/fbtft-core.c
>> index 9e7b84071174..dc967bdeabe8 100644
>> --- a/drivers/staging/fbtft/fbtft-core.c
>> +++ b/drivers/staging/fbtft/fbtft-core.c
>> @@ -365,9 +365,14 @@ static int fbtft_fb_setcolreg(unsigned int regno,
>> unsigned int red,
>> unsigned int val;
>> int ret = 1;
>> +#ifdef CONFIG_FB_DEVICE
>> dev_dbg(info->dev,
>
> Rather use fb_dbg() [1] and similar helpers for logging. They only need
> the info pointer and do the correct output by themselves.
>
> [1] https://elixir.bootlin.com/linux/v6.18/source/include/linux/fb.h#L895
Thank you for this pointer - I actually didnt now this existed. Will do v2.
^ permalink raw reply
* Re: [PATCH 0/3] fbdev: Guard sysfs interfaces under CONFIG_FB_DEVICE
From: Chintan Patel @ 2025-12-10 4:26 UTC (permalink / raw)
To: Andy Shevchenko, Helge Deller
Cc: Thomas Zimmermann, linux-fbdev, linux-staging, linux-omap,
linux-kernel, dri-devel, andy, gregkh
In-Reply-To: <CAHp75Vds8GP+daMe9WcEbOaNT91kMHUjidzGUN-1_kVDuWBtLw@mail.gmail.com>
On 12/9/25 06:25, Andy Shevchenko wrote:
> On Tue, Dec 9, 2025 at 10:23 AM Helge Deller <deller@gmx.de> wrote:
>> On 12/9/25 08:27, Thomas Zimmermann wrote:
>
> ...
>
>> This whole series adds a whole lot of ifdef'ery, which I think is the
>> worst approach. It makes the code less readable and leads to two code
>> paths, which may trigger different build errors depending on the config.
>>
>> I'm sure it must be possible to do the same without adding more #ifdefs,
>> e.g. by introducing a function like dev_of_fbinfo(fbinfo) which
>> simply returns NULL for the FB_DEVICE=n case. Then, that value can be tested
>> like
>> if (dev_of_fbinfo(fbinfo))
>> {...do-the-things...}
>> For the FB_DEVICE=n case this will then be optimized out by the compiler,
>> while you still have full compiler syntax checking.
>>
>> Thoughts?
>
> I second you. I am also not a fan of ifdeffery when it can be avoided.
>
Thank you for the review! Will do the change.
^ permalink raw reply
* Re: [PATCH 14/19] video/vga: Add VGA_IS0_R
From: kernel test robot @ 2025-12-10 14:13 UTC (permalink / raw)
To: Ville Syrjala, intel-gfx
Cc: oe-kbuild-all, intel-xe, Helge Deller, linux-fbdev, dri-devel
In-Reply-To: <20251208182637.334-15-ville.syrjala@linux.intel.com>
Hi Ville,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-tip/drm-tip]
[cannot apply to drm-i915/for-linux-next drm-i915/for-linux-next-fixes drm-xe/drm-xe-next linus/master v6.18 next-20251210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Ville-Syrjala/drm-i915-vga-Register-vgaarb-client-later/20251209-195929
base: https://gitlab.freedesktop.org/drm/tip.git drm-tip
patch link: https://lore.kernel.org/r/20251208182637.334-15-ville.syrjala%40linux.intel.com
patch subject: [PATCH 14/19] video/vga: Add VGA_IS0_R
config: parisc-randconfig-002-20251210 (https://download.01.org/0day-ci/archive/20251210/202512102159.xsvvXCXy-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251210/202512102159.xsvvXCXy-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512102159.xsvvXCXy-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from include/linux/svga.h:6,
from drivers/video/fbdev/arkfb.c:24:
include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
In file included from drivers/video/fbdev/arkfb.c:28:
include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
drivers/video/fbdev/arkfb.c:68:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_h_total_regs[] = {{0x00, 0, 7}, {0x41, 7, 7}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:69:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_h_display_regs[] = {{0x01, 0, 7}, {0x41, 6, 6}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:70:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_h_blank_start_regs[] = {{0x02, 0, 7}, {0x41, 5, 5}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:71:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7 }, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:72:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_h_sync_start_regs[] = {{0x04, 0, 7}, {0x41, 4, 4}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:73:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:75:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x40, 7, 7}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:76:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x40, 6, 6}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:77:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x40, 5, 5}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:79:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:80:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x40, 4, 4}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:81:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:83:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:84:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:85:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset ark_offset_regs[] = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END};
^~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c: In function 'arkfb_tilecursor':
>> drivers/video/fbdev/arkfb.c:152:21: error: dereferencing pointer to incomplete type 'struct arkfb_info'
svga_tilecursor(par->state.vgabase, info, cursor);
^~
drivers/video/fbdev/arkfb.c: At top level:
drivers/video/fbdev/arkfb.c:303:29: warning: 'struct dac_info' declared inside parameter list will not be visible outside of this definition or declaration
int (*dac_get_mode)(struct dac_info *info);
^~~~~~~~
drivers/video/fbdev/arkfb.c:304:29: warning: 'struct dac_info' declared inside parameter list will not be visible outside of this definition or declaration
int (*dac_set_mode)(struct dac_info *info, int mode);
^~~~~~~~
drivers/video/fbdev/arkfb.c:305:29: warning: 'struct dac_info' declared inside parameter list will not be visible outside of this definition or declaration
int (*dac_get_freq)(struct dac_info *info, int channel);
^~~~~~~~
drivers/video/fbdev/arkfb.c:306:29: warning: 'struct dac_info' declared inside parameter list will not be visible outside of this definition or declaration
int (*dac_set_freq)(struct dac_info *info, int channel, u32 freq);
^~~~~~~~
drivers/video/fbdev/arkfb.c:307:29: warning: 'struct dac_info' declared inside parameter list will not be visible outside of this definition or declaration
void (*dac_release)(struct dac_info *info);
^~~~~~~~
drivers/video/fbdev/arkfb.c: In function 'dac_set_mode':
drivers/video/fbdev/arkfb.c:339:36: error: passing argument 1 of 'info->dacops->dac_set_mode' from incompatible pointer type [-Werror=incompatible-pointer-types]
return info->dacops->dac_set_mode(info, mode);
^~~~
drivers/video/fbdev/arkfb.c:339:36: note: expected 'struct dac_info *' but argument is of type 'struct dac_info *'
drivers/video/fbdev/arkfb.c: In function 'dac_set_freq':
drivers/video/fbdev/arkfb.c:344:36: error: passing argument 1 of 'info->dacops->dac_set_freq' from incompatible pointer type [-Werror=incompatible-pointer-types]
return info->dacops->dac_set_freq(info, channel, freq);
^~~~
drivers/video/fbdev/arkfb.c:344:36: note: expected 'struct dac_info *' but argument is of type 'struct dac_info *'
drivers/video/fbdev/arkfb.c: In function 'dac_release':
drivers/video/fbdev/arkfb.c:349:28: error: passing argument 1 of 'info->dacops->dac_release' from incompatible pointer type [-Werror=incompatible-pointer-types]
info->dacops->dac_release(info);
^~~~
drivers/video/fbdev/arkfb.c:349:28: note: expected 'struct dac_info *' but argument is of type 'struct dac_info *'
drivers/video/fbdev/arkfb.c: At top level:
drivers/video/fbdev/arkfb.c:426:18: error: initialization of 'int (*)(struct dac_info *, int)' from incompatible pointer type 'int (*)(struct dac_info *, int)' [-Werror=incompatible-pointer-types]
.dac_set_mode = ics5342_set_mode,
^~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:426:18: note: (near initialization for 'ics5342_ops.dac_set_mode')
drivers/video/fbdev/arkfb.c:427:18: error: initialization of 'int (*)(struct dac_info *, int, u32)' {aka 'int (*)(struct dac_info *, int, unsigned int)'} from incompatible pointer type 'int (*)(struct dac_info *, int, u32)' {aka 'int (*)(struct dac_info *, int, unsigned int)'} [-Werror=incompatible-pointer-types]
.dac_set_freq = ics5342_set_freq,
^~~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:427:18: note: (near initialization for 'ics5342_ops.dac_set_freq')
drivers/video/fbdev/arkfb.c:428:17: error: initialization of 'void (*)(struct dac_info *)' from incompatible pointer type 'void (*)(struct dac_info *)' [-Werror=incompatible-pointer-types]
.dac_release = ics5342_release
^~~~~~~~~~~~~~~
drivers/video/fbdev/arkfb.c:428:17: note: (near initialization for 'ics5342_ops.dac_release')
drivers/video/fbdev/arkfb.c: In function 'ark_dac_read_regs':
drivers/video/fbdev/arkfb.c:461:23: error: dereferencing pointer to incomplete type 'struct arkfb_info'
regval = vga_rseq(par->state.vgabase, 0x1C);
^~
drivers/video/fbdev/arkfb.c: In function 'ark_dac_write_regs':
drivers/video/fbdev/arkfb.c:480:23: error: dereferencing pointer to incomplete type 'struct arkfb_info'
regval = vga_rseq(par->state.vgabase, 0x1C);
^~
drivers/video/fbdev/arkfb.c: In function 'ark_set_pixclock':
drivers/video/fbdev/arkfb.c:498:27: error: dereferencing pointer to incomplete type 'struct arkfb_info'
int rv = dac_set_freq(par->dac, 0, 1000000000 / pixclock);
^~
In file included from include/linux/seqlock.h:19,
from include/linux/mmzone.h:17,
from include/linux/gfp.h:7,
from include/linux/umh.h:4,
from include/linux/kmod.h:9,
from include/linux/module.h:18,
from drivers/video/fbdev/arkfb.c:15:
drivers/video/fbdev/arkfb.c: In function 'arkfb_open':
drivers/video/fbdev/arkfb.c:516:18: error: dereferencing pointer to incomplete type 'struct arkfb_info'
mutex_lock(&(par->open_lock));
^~
include/linux/mutex.h:168:44: note: in definition of macro 'mutex_lock'
#define mutex_lock(lock) mutex_lock_nested(lock, 0)
^~~~
drivers/video/fbdev/arkfb.c: In function 'arkfb_release':
drivers/video/fbdev/arkfb.c:540:18: error: dereferencing pointer to incomplete type 'struct arkfb_info'
mutex_lock(&(par->open_lock));
^~
include/linux/mutex.h:168:44: note: in definition of macro 'mutex_lock'
#define mutex_lock(lock) mutex_lock_nested(lock, 0)
^~~~
drivers/video/fbdev/arkfb.c: In function 'arkfb_set_par':
drivers/video/fbdev/arkfb.c:658:20: error: dereferencing pointer to incomplete type 'struct arkfb_info'
svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80);
^~
drivers/video/fbdev/arkfb.c: In function 'arkfb_blank':
drivers/video/fbdev/arkfb.c:881:21: error: dereferencing pointer to incomplete type 'struct arkfb_info'
svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
^~
drivers/video/fbdev/arkfb.c: In function 'arkfb_pan_display':
drivers/video/fbdev/arkfb.c:920:21: error: dereferencing pointer to incomplete type 'struct arkfb_info'
svga_wcrt_multi(par->state.vgabase, ark_start_address_regs, offset);
^~
drivers/video/fbdev/arkfb.c: In function 'ark_pci_probe':
drivers/video/fbdev/arkfb.c:973:34: error: invalid application of 'sizeof' to incomplete type 'struct arkfb_info'
info = framebuffer_alloc(sizeof(struct arkfb_info), &(dev->dev));
^~~~~~
In file included from include/linux/seqlock.h:19,
from include/linux/mmzone.h:17,
from include/linux/gfp.h:7,
from include/linux/umh.h:4,
from include/linux/kmod.h:9,
--
In file included from include/linux/svga.h:6,
from drivers/video/fbdev/vt8623fb.c:24:
include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
In file included from drivers/video/fbdev/vt8623fb.c:28:
include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
?
^
drivers/video/fbdev/vt8623fb.c:66:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:67:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:68:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:69:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:70:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:71:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:73:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:74:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:75:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:76:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:77:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:78:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:80:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:81:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:82:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:83:32: error: array type has incomplete element type 'struct vga_regset'
static const struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623fb_tilecursor':
>> drivers/video/fbdev/vt8623fb.c:119:21: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
svga_tilecursor(par->state.vgabase, info, cursor);
^~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623_set_pixclock':
drivers/video/fbdev/vt8623fb.c:265:20: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
regval = vga_r(par->state.vgabase, VGA_MIS_R);
^~
In file included from include/linux/seqlock.h:19,
from include/linux/mmzone.h:17,
from include/linux/gfp.h:7,
from include/linux/umh.h:4,
from include/linux/kmod.h:9,
from include/linux/module.h:18,
from drivers/video/fbdev/vt8623fb.c:16:
drivers/video/fbdev/vt8623fb.c: In function 'vt8623fb_open':
drivers/video/fbdev/vt8623fb.c:284:18: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
mutex_lock(&(par->open_lock));
^~
include/linux/mutex.h:168:44: note: in definition of macro 'mutex_lock'
#define mutex_lock(lock) mutex_lock_nested(lock, 0)
^~~~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623fb_release':
drivers/video/fbdev/vt8623fb.c:306:18: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
mutex_lock(&(par->open_lock));
^~
include/linux/mutex.h:168:44: note: in definition of macro 'mutex_lock'
#define mutex_lock(lock) mutex_lock_nested(lock, 0)
^~~~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623fb_set_par':
drivers/video/fbdev/vt8623fb.c:431:20: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
svga_wseq_mask(par->state.vgabase, 0x10, 0x01, 0x01);
^~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623fb_blank':
drivers/video/fbdev/vt8623fb.c:593:21: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30);
^~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623fb_pan_display':
drivers/video/fbdev/vt8623fb.c:639:21: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, offset);
^~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623_pci_probe':
drivers/video/fbdev/vt8623fb.c:690:34: error: invalid application of 'sizeof' to incomplete type 'struct vt8623fb_info'
info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev));
^~~~~~
In file included from include/linux/seqlock.h:19,
from include/linux/mmzone.h:17,
from include/linux/gfp.h:7,
from include/linux/umh.h:4,
from include/linux/kmod.h:9,
from include/linux/module.h:18,
from drivers/video/fbdev/vt8623fb.c:16:
drivers/video/fbdev/vt8623fb.c:695:17: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
mutex_init(&par->open_lock);
^~
include/linux/mutex.h:64:16: note: in definition of macro 'mutex_init'
__mutex_init((mutex), #mutex, &__key); \
^~~~~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623_pci_remove':
drivers/video/fbdev/vt8623fb.c:823:23: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
arch_phys_wc_del(par->wc_cookie);
^~
In file included from include/linux/seqlock.h:19,
from include/linux/mmzone.h:17,
from include/linux/gfp.h:7,
from include/linux/umh.h:4,
from include/linux/kmod.h:9,
from include/linux/module.h:18,
from drivers/video/fbdev/vt8623fb.c:16:
drivers/video/fbdev/vt8623fb.c: In function 'vt8623_pci_suspend':
drivers/video/fbdev/vt8623fb.c:847:18: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
mutex_lock(&(par->open_lock));
^~
include/linux/mutex.h:168:44: note: in definition of macro 'mutex_lock'
#define mutex_lock(lock) mutex_lock_nested(lock, 0)
^~~~
drivers/video/fbdev/vt8623fb.c: In function 'vt8623_pci_resume':
drivers/video/fbdev/vt8623fb.c:874:18: error: dereferencing pointer to incomplete type 'struct vt8623fb_info'
mutex_lock(&(par->open_lock));
^~
include/linux/mutex.h:168:44: note: in definition of macro 'mutex_lock'
#define mutex_lock(lock) mutex_lock_nested(lock, 0)
^~~~
At top level:
drivers/video/fbdev/vt8623fb.c:83:32: warning: 'vt8623_start_address_regs' defined but not used [-Wunused-variable]
static const struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:82:32: warning: 'vt8623_fetch_count_regs' defined but not used [-Wunused-variable]
static const struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:81:32: warning: 'vt8623_line_compare_regs' defined but not used [-Wunused-variable]
static const struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:80:32: warning: 'vt8623_offset_regs' defined but not used [-Wunused-variable]
static const struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:78:32: warning: 'vt8623_v_sync_end_regs' defined but not used [-Wunused-variable]
static const struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~
drivers/video/fbdev/vt8623fb.c:77:32: warning: 'vt8623_v_sync_start_regs' defined but not used [-Wunused-variable]
static const struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
^~~~~~~~~~~~~~~~~~~~~~~~
..
vim +152 drivers/video/fbdev/arkfb.c
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 82
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 83 static const struct vga_regset ark_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END};
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 @84 static const struct vga_regset ark_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END};
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 85 static const struct vga_regset ark_offset_regs[] = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END};
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 86
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 87 static const struct svga_timing_regs ark_timing_regs = {
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 88 ark_h_total_regs, ark_h_display_regs, ark_h_blank_start_regs,
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 89 ark_h_blank_end_regs, ark_h_sync_start_regs, ark_h_sync_end_regs,
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 90 ark_v_total_regs, ark_v_display_regs, ark_v_blank_start_regs,
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 91 ark_v_blank_end_regs, ark_v_sync_start_regs, ark_v_sync_end_regs,
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 92 };
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 93
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 94
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 95 /* ------------------------------------------------------------------------- */
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 96
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 97
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 98 /* Module parameters */
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 99
48c68c4f1b5424 drivers/video/arkfb.c Greg Kroah-Hartman 2012-12-21 100 static char *mode_option = "640x480-8@60";
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 101
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 102 MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>");
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 103 MODULE_LICENSE("GPL");
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 104 MODULE_DESCRIPTION("fbdev driver for ARK 2000PV");
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 105
1abf91729faf2f drivers/video/arkfb.c Krzysztof Helt 2008-04-28 106 module_param(mode_option, charp, 0444);
1abf91729faf2f drivers/video/arkfb.c Krzysztof Helt 2008-04-28 107 MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
1abf91729faf2f drivers/video/arkfb.c Krzysztof Helt 2008-04-28 108 module_param_named(mode, mode_option, charp, 0444);
1abf91729faf2f drivers/video/arkfb.c Krzysztof Helt 2008-04-28 109 MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)");
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 110
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 111 static int threshold = 4;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 112
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 113 module_param(threshold, int, 0644);
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 114 MODULE_PARM_DESC(threshold, "FIFO threshold");
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 115
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 116
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 117 /* ------------------------------------------------------------------------- */
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 118
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 119
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 120 static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map)
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 121 {
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 122 const u8 *font = map->data;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 123 u8 __iomem *fb = (u8 __iomem *)info->screen_base;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 124 int i, c;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 125
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 126 if ((map->width != 8) || (map->height != 16) ||
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 127 (map->depth != 1) || (map->length != 256)) {
31b6780c15a4e3 drivers/video/arkfb.c Joe Perches 2013-09-19 128 fb_err(info, "unsupported font parameters: width %d, height %d, depth %d, length %d\n",
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 129 map->width, map->height, map->depth, map->length);
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 130 return;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 131 }
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 132
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 133 fb += 2;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 134 for (c = 0; c < map->length; c++) {
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 135 for (i = 0; i < map->height; i++) {
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 136 fb_writeb(font[i], &fb[i * 4]);
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 137 fb_writeb(font[i], &fb[i * 4 + (128 * 8)]);
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 138 }
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 139 fb += 128;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 140
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 141 if ((c % 8) == 7)
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 142 fb += 128*8;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 143
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 144 font += map->height;
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 145 }
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 146 }
681e14730c73cc drivers/video/arkfb.c Ondrej Zajicek 2007-05-09 147
55db0923884554 drivers/video/arkfb.c David Miller 2011-01-11 148 static void arkfb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
55db0923884554 drivers/video/arkfb.c David Miller 2011-01-11 149 {
55db0923884554 drivers/video/arkfb.c David Miller 2011-01-11 150 struct arkfb_info *par = info->par;
55db0923884554 drivers/video/arkfb.c David Miller 2011-01-11 151
55db0923884554 drivers/video/arkfb.c David Miller 2011-01-11 @152 svga_tilecursor(par->state.vgabase, info, cursor);
55db0923884554 drivers/video/arkfb.c David Miller 2011-01-11 153 }
55db0923884554 drivers/video/arkfb.c David Miller 2011-01-11 154
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH 14/19] video/vga: Add VGA_IS0_R
From: kernel test robot @ 2025-12-10 14:24 UTC (permalink / raw)
To: Ville Syrjala, intel-gfx
Cc: oe-kbuild-all, intel-xe, Helge Deller, linux-fbdev, dri-devel
In-Reply-To: <20251208182637.334-15-ville.syrjala@linux.intel.com>
Hi Ville,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-tip/drm-tip]
[cannot apply to drm-i915/for-linux-next drm-i915/for-linux-next-fixes drm-xe/drm-xe-next linus/master v6.18 next-20251210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Ville-Syrjala/drm-i915-vga-Register-vgaarb-client-later/20251209-195929
base: https://gitlab.freedesktop.org/drm/tip.git drm-tip
patch link: https://lore.kernel.org/r/20251208182637.334-15-ville.syrjala%40linux.intel.com
patch subject: [PATCH 14/19] video/vga: Add VGA_IS0_R
config: s390-randconfig-002-20251210 (https://download.01.org/0day-ci/archive/20251210/202512102200.KIAC3RLu-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 9.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251210/202512102200.KIAC3RLu-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512102200.KIAC3RLu-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/video/vgastate.c:20:
include/video/vga.h:489:1: error: expected identifier or '(' before '?' token
489 | ?
| ^
drivers/video/vgastate.c: In function 'save_vga_text':
>> drivers/video/vgastate.c:89:9: error: dereferencing pointer to incomplete type 'struct regstate'
89 | saved->vga_font0[i] = vga_r(fbbase, i);
| ^~
drivers/video/vgastate.c: In function 'restore_vga_text':
drivers/video/vgastate.c:175:26: error: dereferencing pointer to incomplete type 'struct regstate'
175 | vga_w(fbbase, i, saved->vga_font0[i]);
| ^~
drivers/video/vgastate.c: In function 'save_vga_mode':
drivers/video/vgastate.c:232:7: error: dereferencing pointer to incomplete type 'struct regstate'
232 | saved->misc = vga_r(state->vgabase, VGA_MIS_R);
| ^~
drivers/video/vgastate.c: In function 'restore_vga_mode':
drivers/video/vgastate.c:263:40: error: dereferencing pointer to incomplete type 'struct regstate'
263 | vga_w(state->vgabase, VGA_MIS_W, saved->misc);
| ^~
drivers/video/vgastate.c: In function 'save_vga_cmap':
drivers/video/vgastate.c:319:8: error: dereferencing pointer to incomplete type 'struct regstate'
319 | saved->vga_cmap[i] = vga_r(state->vgabase, VGA_PEL_D);
| ^~
drivers/video/vgastate.c: In function 'restore_vga_cmap':
drivers/video/vgastate.c:332:41: error: dereferencing pointer to incomplete type 'struct regstate'
332 | vga_w(state->vgabase, VGA_PEL_D, saved->vga_cmap[i]);
| ^~
drivers/video/vgastate.c: In function 'vga_cleanup':
drivers/video/vgastate.c:340:14: error: dereferencing pointer to incomplete type 'struct regstate'
340 | vfree(saved->vga_font0);
| ^~
In file included from include/linux/workqueue.h:9,
from include/linux/mm_types.h:19,
from include/linux/mmzone.h:22,
from include/linux/gfp.h:7,
from include/linux/umh.h:4,
from include/linux/kmod.h:9,
from include/linux/module.h:18,
from drivers/video/vgastate.c:16:
drivers/video/vgastate.c: In function 'save_vga':
drivers/video/vgastate.c:354:25: error: invalid application of 'sizeof' to incomplete type 'struct regstate'
354 | saved = kzalloc(sizeof(struct regstate), GFP_KERNEL);
| ^~~~~~
include/linux/alloc_tag.h:251:9: note: in definition of macro 'alloc_hooks_tag'
251 | typeof(_do_alloc) _res; \
| ^~~~~~~~~
include/linux/slab.h:1096:25: note: in expansion of macro 'alloc_hooks'
1096 | #define kzalloc(...) alloc_hooks(kzalloc_noprof(__VA_ARGS__))
| ^~~~~~~~~~~
drivers/video/vgastate.c:354:10: note: in expansion of macro 'kzalloc'
354 | saved = kzalloc(sizeof(struct regstate), GFP_KERNEL);
| ^~~~~~~
drivers/video/vgastate.c:354:25: error: invalid application of 'sizeof' to incomplete type 'struct regstate'
354 | saved = kzalloc(sizeof(struct regstate), GFP_KERNEL);
| ^~~~~~
include/linux/alloc_tag.h:255:10: note: in definition of macro 'alloc_hooks_tag'
255 | _res = _do_alloc; \
| ^~~~~~~~~
include/linux/slab.h:1096:25: note: in expansion of macro 'alloc_hooks'
1096 | #define kzalloc(...) alloc_hooks(kzalloc_noprof(__VA_ARGS__))
| ^~~~~~~~~~~
drivers/video/vgastate.c:354:10: note: in expansion of macro 'kzalloc'
354 | saved = kzalloc(sizeof(struct regstate), GFP_KERNEL);
| ^~~~~~~
drivers/video/vgastate.c:354:25: error: invalid application of 'sizeof' to incomplete type 'struct regstate'
354 | saved = kzalloc(sizeof(struct regstate), GFP_KERNEL);
| ^~~~~~
include/linux/alloc_tag.h:258:10: note: in definition of macro 'alloc_hooks_tag'
258 | _res = _do_alloc; \
| ^~~~~~~~~
include/linux/slab.h:1096:25: note: in expansion of macro 'alloc_hooks'
1096 | #define kzalloc(...) alloc_hooks(kzalloc_noprof(__VA_ARGS__))
| ^~~~~~~~~~~
drivers/video/vgastate.c:354:10: note: in expansion of macro 'kzalloc'
354 | saved = kzalloc(sizeof(struct regstate), GFP_KERNEL);
| ^~~~~~~
drivers/video/vgastate.c:354:8: warning: assignment to 'struct regstate *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
354 | saved = kzalloc(sizeof(struct regstate), GFP_KERNEL);
| ^
drivers/video/vgastate.c:362:8: error: dereferencing pointer to incomplete type 'struct regstate'
362 | saved->vga_cmap = vmalloc(768);
| ^~
vim +89 drivers/video/vgastate.c
^1da177e4c3f41 Linus Torvalds 2005-04-16 47
^1da177e4c3f41 Linus Torvalds 2005-04-16 48 static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
^1da177e4c3f41 Linus Torvalds 2005-04-16 49 {
^1da177e4c3f41 Linus Torvalds 2005-04-16 50 struct regstate *saved = (struct regstate *) state->vidstate;
^1da177e4c3f41 Linus Torvalds 2005-04-16 51 int i;
^1da177e4c3f41 Linus Torvalds 2005-04-16 52 u8 misc, attr10, gr4, gr5, gr6, seq1, seq2, seq4;
0449359f053829 Ondrej Zajicek 2007-05-08 53 unsigned short iobase;
^1da177e4c3f41 Linus Torvalds 2005-04-16 54
^1da177e4c3f41 Linus Torvalds 2005-04-16 55 /* if in graphics mode, no need to save */
0449359f053829 Ondrej Zajicek 2007-05-08 56 misc = vga_r(state->vgabase, VGA_MIS_R);
0449359f053829 Ondrej Zajicek 2007-05-08 57 iobase = (misc & 1) ? 0x3d0 : 0x3b0;
0449359f053829 Ondrej Zajicek 2007-05-08 58
0449359f053829 Ondrej Zajicek 2007-05-08 59 vga_r(state->vgabase, iobase + 0xa);
0449359f053829 Ondrej Zajicek 2007-05-08 60 vga_w(state->vgabase, VGA_ATT_W, 0x00);
^1da177e4c3f41 Linus Torvalds 2005-04-16 61 attr10 = vga_rattr(state->vgabase, 0x10);
0449359f053829 Ondrej Zajicek 2007-05-08 62 vga_r(state->vgabase, iobase + 0xa);
0449359f053829 Ondrej Zajicek 2007-05-08 63 vga_w(state->vgabase, VGA_ATT_W, 0x20);
0449359f053829 Ondrej Zajicek 2007-05-08 64
^1da177e4c3f41 Linus Torvalds 2005-04-16 65 if (attr10 & 1)
^1da177e4c3f41 Linus Torvalds 2005-04-16 66 return;
^1da177e4c3f41 Linus Torvalds 2005-04-16 67
^1da177e4c3f41 Linus Torvalds 2005-04-16 68 /* save regs */
^1da177e4c3f41 Linus Torvalds 2005-04-16 69 gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
^1da177e4c3f41 Linus Torvalds 2005-04-16 70 gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE);
^1da177e4c3f41 Linus Torvalds 2005-04-16 71 gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
^1da177e4c3f41 Linus Torvalds 2005-04-16 72 seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
^1da177e4c3f41 Linus Torvalds 2005-04-16 73 seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
^1da177e4c3f41 Linus Torvalds 2005-04-16 74
^1da177e4c3f41 Linus Torvalds 2005-04-16 75 /* blank screen */
^1da177e4c3f41 Linus Torvalds 2005-04-16 76 seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
^1da177e4c3f41 Linus Torvalds 2005-04-16 77 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
^1da177e4c3f41 Linus Torvalds 2005-04-16 78 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5);
^1da177e4c3f41 Linus Torvalds 2005-04-16 79 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
^1da177e4c3f41 Linus Torvalds 2005-04-16 80
^1da177e4c3f41 Linus Torvalds 2005-04-16 81 /* save font at plane 2 */
^1da177e4c3f41 Linus Torvalds 2005-04-16 82 if (state->flags & VGA_SAVE_FONT0) {
^1da177e4c3f41 Linus Torvalds 2005-04-16 83 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4);
^1da177e4c3f41 Linus Torvalds 2005-04-16 84 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
^1da177e4c3f41 Linus Torvalds 2005-04-16 85 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
^1da177e4c3f41 Linus Torvalds 2005-04-16 86 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
^1da177e4c3f41 Linus Torvalds 2005-04-16 87 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
^1da177e4c3f41 Linus Torvalds 2005-04-16 88 for (i = 0; i < 4 * 8192; i++)
^1da177e4c3f41 Linus Torvalds 2005-04-16 @89 saved->vga_font0[i] = vga_r(fbbase, i);
^1da177e4c3f41 Linus Torvalds 2005-04-16 90 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 91
^1da177e4c3f41 Linus Torvalds 2005-04-16 92 /* save font at plane 3 */
^1da177e4c3f41 Linus Torvalds 2005-04-16 93 if (state->flags & VGA_SAVE_FONT1) {
^1da177e4c3f41 Linus Torvalds 2005-04-16 94 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8);
^1da177e4c3f41 Linus Torvalds 2005-04-16 95 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
^1da177e4c3f41 Linus Torvalds 2005-04-16 96 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
^1da177e4c3f41 Linus Torvalds 2005-04-16 97 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
^1da177e4c3f41 Linus Torvalds 2005-04-16 98 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
^1da177e4c3f41 Linus Torvalds 2005-04-16 99 for (i = 0; i < state->memsize; i++)
^1da177e4c3f41 Linus Torvalds 2005-04-16 100 saved->vga_font1[i] = vga_r(fbbase, i);
^1da177e4c3f41 Linus Torvalds 2005-04-16 101 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 102
^1da177e4c3f41 Linus Torvalds 2005-04-16 103 /* save font at plane 0/1 */
^1da177e4c3f41 Linus Torvalds 2005-04-16 104 if (state->flags & VGA_SAVE_TEXT) {
^1da177e4c3f41 Linus Torvalds 2005-04-16 105 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
^1da177e4c3f41 Linus Torvalds 2005-04-16 106 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
^1da177e4c3f41 Linus Torvalds 2005-04-16 107 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
^1da177e4c3f41 Linus Torvalds 2005-04-16 108 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
^1da177e4c3f41 Linus Torvalds 2005-04-16 109 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
^1da177e4c3f41 Linus Torvalds 2005-04-16 110 for (i = 0; i < 8192; i++)
^1da177e4c3f41 Linus Torvalds 2005-04-16 111 saved->vga_text[i] = vga_r(fbbase, i);
^1da177e4c3f41 Linus Torvalds 2005-04-16 112
^1da177e4c3f41 Linus Torvalds 2005-04-16 113 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
^1da177e4c3f41 Linus Torvalds 2005-04-16 114 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
^1da177e4c3f41 Linus Torvalds 2005-04-16 115 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
^1da177e4c3f41 Linus Torvalds 2005-04-16 116 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
^1da177e4c3f41 Linus Torvalds 2005-04-16 117 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
^1da177e4c3f41 Linus Torvalds 2005-04-16 118 for (i = 0; i < 8192; i++)
^1da177e4c3f41 Linus Torvalds 2005-04-16 119 saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i);
^1da177e4c3f41 Linus Torvalds 2005-04-16 120 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 121
^1da177e4c3f41 Linus Torvalds 2005-04-16 122 /* restore regs */
^1da177e4c3f41 Linus Torvalds 2005-04-16 123 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
^1da177e4c3f41 Linus Torvalds 2005-04-16 124 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
^1da177e4c3f41 Linus Torvalds 2005-04-16 125
^1da177e4c3f41 Linus Torvalds 2005-04-16 126 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
^1da177e4c3f41 Linus Torvalds 2005-04-16 127 vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5);
^1da177e4c3f41 Linus Torvalds 2005-04-16 128 vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6);
^1da177e4c3f41 Linus Torvalds 2005-04-16 129
^1da177e4c3f41 Linus Torvalds 2005-04-16 130 /* unblank screen */
^1da177e4c3f41 Linus Torvalds 2005-04-16 131 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
^1da177e4c3f41 Linus Torvalds 2005-04-16 132 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5));
^1da177e4c3f41 Linus Torvalds 2005-04-16 133 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
^1da177e4c3f41 Linus Torvalds 2005-04-16 134
^1da177e4c3f41 Linus Torvalds 2005-04-16 135 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1);
^1da177e4c3f41 Linus Torvalds 2005-04-16 136 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 137
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH 0/8] Add support for Advantech EIO MFD series devices
From: Ramiro Oliveira @ 2025-12-12 16:40 UTC (permalink / raw)
To: Lee Jones, Linus Walleij, Bartosz Golaszewski, Guenter Roeck,
Andi Shyti, Daniel Thompson, Jingoo Han, Helge Deller,
Wim Van Sebroeck, Rafael J. Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba
Cc: linux-kernel, linux-gpio, linux-hwmon, linux-i2c, dri-devel,
linux-fbdev, linux-watchdog, linux-pm, Wenkai Chung,
Francisco Aragon-Trivino, Hongzhi Wang, Mikhail Tsukerman,
Thomas Kastner, Ramiro Oliveira
This series implements a set of drivers allowing to support the
Advantech EIO-2xx series of devices.
This includes GPIO, hwmon, I2C bus, backlight controller, watchdog,
thermal and a fan driver.
This series of patches targets several different subsystems, but the MFD
subsystem is the main target.
Signed-off-by: Ramiro Oliveira <ramiro.oliveira@advantech.com>
---
Ramiro Oliveira (8):
Add Advantech EIO MFD driver
Add Advantech EIO GPIO driver
Add Advantech EIO Hardware Monitor driver
Add Advantech EIO I2C driver
Add Advantech EIO Backlight driver
Add Advantech EIO Watchdog driver
Add Advantech EIO Thermal driver
Add Advantech EIO Fan driver
MAINTAINERS | 13 +
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-eio.c | 273 +++++++++
drivers/hwmon/Kconfig | 10 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/eio-hwmon.c | 344 ++++++++++++
drivers/i2c/busses/Kconfig | 6 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-eio.c | 1142 ++++++++++++++++++++++++++++++++++++++
drivers/mfd/Kconfig | 10 +
drivers/mfd/Makefile | 1 +
drivers/mfd/eio_core.c | 621 +++++++++++++++++++++
drivers/thermal/Kconfig | 17 +
drivers/thermal/Makefile | 2 +
drivers/thermal/eio_fan.c | 490 ++++++++++++++++
drivers/thermal/eio_thermal.c | 352 ++++++++++++
drivers/video/backlight/Kconfig | 6 +
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/eio_bl.c | 268 +++++++++
drivers/watchdog/Kconfig | 7 +
drivers/watchdog/Makefile | 1 +
drivers/watchdog/eio_wdt.c | 672 ++++++++++++++++++++++
include/linux/mfd/eio.h | 127 +++++
24 files changed, 4372 insertions(+)
---
base-commit: d9771d0dbe18dd643760431870a6abf9b0866bb0
change-id: 20251212-upstream-v1-81338c603f94
Best regards,
--
Ramiro Oliveira <ramiro.oliveira@advantech.com>
^ permalink raw reply
* [PATCH 1/8] Add Advantech EIO MFD driver
From: Ramiro Oliveira @ 2025-12-12 16:40 UTC (permalink / raw)
To: Lee Jones, Linus Walleij, Bartosz Golaszewski, Guenter Roeck,
Andi Shyti, Daniel Thompson, Jingoo Han, Helge Deller,
Wim Van Sebroeck, Rafael J. Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba
Cc: linux-kernel, linux-gpio, linux-hwmon, linux-i2c, dri-devel,
linux-fbdev, linux-watchdog, linux-pm, Wenkai Chung,
Francisco Aragon-Trivino, Hongzhi Wang, Mikhail Tsukerman,
Thomas Kastner, Ramiro Oliveira
In-Reply-To: <20251212-upstream-v1-v1-0-d50d40ec8d8a@advantech.com>
Creating the MFD core driver for Advantech EIO, all other drivers (GPIO,
I2C, etc) depend on this core driver.
Signed-off-by: Ramiro Oliveira <ramiro.oliveira@advantech.com>
---
MAINTAINERS | 6 +
drivers/mfd/Kconfig | 10 +
drivers/mfd/Makefile | 1 +
drivers/mfd/eio_core.c | 621 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/eio.h | 127 ++++++++++
5 files changed, 765 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 663e86eb9ff1..bd9279796c2f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -616,6 +616,12 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/adv_swbutton.c
+ADVANTECH EIO DRIVER
+M: Ramiro Oliveira <ramiro.oliveira@advantech.com>
+S: Maintained
+F: drivers/mfd/eio_core.c
+F: include/linux/mfd/eio.h
+
ADXL313 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
M: Lucas Stankus <lucas.p.stankus@gmail.com>
S: Supported
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index aace5766b38a..02a0b324eb6a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -506,6 +506,16 @@ config MFD_DLN2
etc. must be enabled in order to use the functionality of
the device.
+config MFD_EIO
+ tristate "Advantech EIO MFD core"
+ select MFD_CORE
+ help
+ This enables support for the Advantech EIO multi-function device.
+ This core driver provides register access and coordination for the
+ EIO's subdevices (GPIO, watchdog, hwmon, thermal, backlight, I2C).
+ This driver supports EIO-IS200, EIO-201, EIO-210 and EIO-211.
+
+
config MFD_ENE_KB3930
tristate "ENE KB3930 Embedded Controller support"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e75e8045c28a..f8c53b55b679 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o
obj-$(CONFIG_MFD_CS42L43) += cs42l43.o
obj-$(CONFIG_MFD_CS42L43_I2C) += cs42l43-i2c.o
obj-$(CONFIG_MFD_CS42L43_SDW) += cs42l43-sdw.o
+obj-$(CONFIG_MFD_EIO) += eio_core.o
obj-$(CONFIG_MFD_ENE_KB3930) += ene-kb3930.o
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o
diff --git a/drivers/mfd/eio_core.c b/drivers/mfd/eio_core.c
new file mode 100644
index 000000000000..7a58c62595a5
--- /dev/null
+++ b/drivers/mfd/eio_core.c
@@ -0,0 +1,621 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Advantech Embedded Controller base Driver
+ *
+ * This driver provides an interface to access the EIO Series EC
+ * firmware via its own Power Management Channel (PMC) for subdrivers:
+ *
+ * A system may have one or two independent EIO devices.
+ *
+ * Copyright (C) 2025 Advantech Co., Ltd.
+ */
+
+#include <linux/delay.h>
+#include <linux/isa.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/mfd/eio.h>
+
+#define TIMEOUT_MAX (10 * USEC_PER_SEC)
+#define TIMEOUT_MIN 200
+#define SLEEP_MAX 200
+#define DEFAULT_TIMEOUT 5000
+
+/**
+ * Timeout: Default timeout in microseconds when a PMC command's
+ * timeout is unspecified. PMC command responses typically range
+ * from 200us to 2ms. 5ms is quite a safe value for timeout. In
+ * In some cases, responses are longer. In such situations, please
+ * adding the timeout parameter loading related sub-drivers or
+ * this core driver (not recommended).
+ */
+static uint timeout = DEFAULT_TIMEOUT;
+module_param(timeout, uint, 0444);
+MODULE_PARM_DESC(timeout, "Default PMC command timeout in usec.\n");
+
+struct eio_dev_port {
+ u16 idx_port;
+ u16 data_port;
+};
+
+static struct eio_dev_port pnp_port[] = {
+ { .idx_port = EIO_PNP_INDEX, .data_port = EIO_PNP_DATA },
+ { .idx_port = EIO_SUB_PNP_INDEX,
+ .data_port = EIO_SUB_PNP_DATA },
+};
+
+static struct mfd_cell mfd_devs[] = {
+ { .name = "eio_wdt" },
+ { .name = "gpio_eio" },
+ { .name = "eio_hwmon" },
+ { .name = "i2c_eio" },
+ { .name = "eio_thermal" },
+ { .name = "eio_fan" },
+ { .name = "eio_bl" },
+};
+
+static const struct regmap_range eio_range[] = {
+ regmap_reg_range(EIO_PNP_INDEX, EIO_PNP_DATA),
+ regmap_reg_range(EIO_SUB_PNP_INDEX, EIO_SUB_PNP_DATA),
+ regmap_reg_range(0x200, 0x3FF),
+};
+
+static const struct regmap_access_table volatile_regs = {
+ .yes_ranges = eio_range,
+ .n_yes_ranges = ARRAY_SIZE(eio_range),
+};
+
+static const struct regmap_config pnp_regmap_config = {
+ .name = "eio_core",
+ .reg_bits = 16,
+ .val_bits = 8,
+ .volatile_table = &volatile_regs,
+ .io_port = true,
+ .cache_type = REGCACHE_NONE,
+};
+
+static struct {
+ char name[32];
+ int cmd;
+ int ctrl;
+ int dev;
+ int size;
+ enum {
+ HEX,
+ NUMBER,
+ PNP_ID,
+ } type;
+
+} attrs[] = {
+ { "board_name", 0x53, 0x10, 0, 16 },
+ { "board_serial", 0x53, 0x1F, 0, 16 },
+ { "board_manufacturer", 0x53, 0x11, 0, 16 },
+ { "board_id", 0x53, 0x1E, 0, 4 },
+ { "firmware_version", 0x53, 0x21, 0, 4 },
+ { "firmware_name", 0x53, 0x22, 0, 16 },
+ { "firmware_build", 0x53, 0x23, 0, 26 },
+ { "firmware_date", 0x53, 0x24, 0, 16 },
+ { "chip_id", 0x53, 0x12, 0, 12 },
+ { "chip_detect", 0x53, 0x15, 0, 12 },
+ { "platform_type", 0x53, 0x13, 0, 16 },
+ { "platform_revision", 0x53, 0x04, 0x44, 4 },
+ { "eapi_version", 0x53, 0x04, 0x64, 4 },
+ { "eapi_id", 0x53, 0x31, 0, 4 },
+ { "boot_count", 0x55, 0x10, 0, 4, NUMBER },
+ { "powerup_hour", 0x55, 0x11, 0, 4, NUMBER },
+ { "pnp_id", 0x53, 0x04, 0x68, 4, PNP_ID },
+};
+
+static ssize_t info_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ uint i;
+
+ for (i = 0; i < ARRAY_SIZE(attrs); i++) {
+ int ret;
+ char str[32] = "";
+ int val;
+
+ struct pmc_op op = {
+ .cmd = attrs[i].cmd,
+ .control = attrs[i].ctrl,
+ .device_id = attrs[i].dev,
+ .payload = (u8 *)str,
+ .size = attrs[i].size,
+ };
+
+ if (strcmp(attr->attr.name, attrs[i].name))
+ continue;
+
+ ret = eio_core_pmc_operation(dev, &op);
+ if (ret)
+ return ret;
+
+ if (attrs[i].size != 4)
+ return sprintf(buf, "%s\n", str);
+
+ val = *(u32 *)str;
+
+ if (attrs[i].type == HEX)
+ return sprintf(buf, "0x%08X\n", val);
+
+ if (attrs[i].type == NUMBER)
+ return sprintf(buf, "%d\n", val);
+
+ /* Should be pnp_id */
+ return sprintf(buf, "%c%c%c, %X\n", (val >> 14 & 0x3F) + 0x40,
+ ((val >> 9 & 0x18) | (val >> 25 & 0x07)) + 0x40,
+ (val >> 20 & 0x1F) + 0x40, val & 0xFFF);
+ }
+
+ return -EINVAL;
+}
+
+#define PMC_DEVICE_ATTR_RO(_name) \
+ static ssize_t _name##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+ { \
+ return info_show(dev, attr, buf); \
+ } \
+ static DEVICE_ATTR_RO(_name)
+
+PMC_DEVICE_ATTR_RO(board_name);
+PMC_DEVICE_ATTR_RO(board_serial);
+PMC_DEVICE_ATTR_RO(board_manufacturer);
+PMC_DEVICE_ATTR_RO(firmware_name);
+PMC_DEVICE_ATTR_RO(firmware_version);
+PMC_DEVICE_ATTR_RO(firmware_build);
+PMC_DEVICE_ATTR_RO(firmware_date);
+PMC_DEVICE_ATTR_RO(chip_id);
+PMC_DEVICE_ATTR_RO(chip_detect);
+PMC_DEVICE_ATTR_RO(platform_type);
+PMC_DEVICE_ATTR_RO(platform_revision);
+PMC_DEVICE_ATTR_RO(board_id);
+PMC_DEVICE_ATTR_RO(eapi_version);
+PMC_DEVICE_ATTR_RO(eapi_id);
+PMC_DEVICE_ATTR_RO(boot_count);
+PMC_DEVICE_ATTR_RO(powerup_hour);
+PMC_DEVICE_ATTR_RO(pnp_id);
+
+static struct attribute *pmc_attrs[] = { &dev_attr_board_name.attr,
+ &dev_attr_board_serial.attr,
+ &dev_attr_board_manufacturer.attr,
+ &dev_attr_firmware_name.attr,
+ &dev_attr_firmware_version.attr,
+ &dev_attr_firmware_build.attr,
+ &dev_attr_firmware_date.attr,
+ &dev_attr_chip_id.attr,
+ &dev_attr_chip_detect.attr,
+ &dev_attr_platform_type.attr,
+ &dev_attr_platform_revision.attr,
+ &dev_attr_board_id.attr,
+ &dev_attr_eapi_version.attr,
+ &dev_attr_eapi_id.attr,
+ &dev_attr_boot_count.attr,
+ &dev_attr_powerup_hour.attr,
+ &dev_attr_pnp_id.attr,
+ NULL };
+
+ATTRIBUTE_GROUPS(pmc);
+
+static unsigned int eio_pnp_read(struct device *dev,
+ struct eio_dev_port *port, u8 idx)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ unsigned int val;
+
+ if (regmap_write(eio->map, port->idx_port, idx))
+ dev_err(dev, "Error port write 0x%X\n", port->idx_port);
+
+ if (regmap_read(eio->map, port->data_port, &val))
+ dev_err(dev, "Error port read 0x%X\n", port->data_port);
+
+ return val;
+}
+
+static void eio_pnp_write(struct device *dev, struct eio_dev_port *port,
+ u8 idx, u8 data)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+
+ if (regmap_write(eio->map, port->idx_port, idx) ||
+ regmap_write(eio->map, port->data_port, data))
+ dev_err(dev, "Error port write 0x%X %X\n", port->idx_port,
+ port->data_port);
+}
+
+static void eio_pnp_enter(struct device *dev, struct eio_dev_port *port)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ /* Write 0x87 to index port twice to unlock IO port */
+ if (regmap_write(eio->map, port->idx_port,
+ EIO_EXT_MODE_ENTER) ||
+ regmap_write(eio->map, port->idx_port, EIO_EXT_MODE_ENTER))
+ dev_err(dev, "Error port write 0x%X\n", port->idx_port);
+}
+
+static void eio_pnp_leave(struct device *dev, struct eio_dev_port *port)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ /* Write 0xAA to index port once to lock IO port */
+ if (regmap_write(eio->map, port->idx_port, EIO_EXT_MODE_EXIT))
+ dev_err(dev, "Error port write 0x%X\n", port->idx_port);
+}
+
+static int pmc_write_data(struct device *dev, int id, u8 value, u16 timeout)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ int ret;
+
+ if (WAIT_IBF(dev, id, timeout))
+ return -ETIME;
+
+ ret = regmap_write(eio->map, eio->pmc[id].data, value);
+ if (ret)
+ dev_err(dev, "Error PMC write %X:%X\n",
+ eio->pmc[id].data, value);
+
+ return ret;
+}
+
+static int pmc_write_cmd(struct device *dev, int id, u8 value, u16 timeout)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ int ret;
+
+ if (WAIT_IBF(dev, id, timeout))
+ return -ETIME;
+
+ ret = regmap_write(eio->map, eio->pmc[id].cmd, value);
+ if (ret)
+ dev_err(dev, "Error PMC write %X:%X\n",
+ eio->pmc[id].cmd, value);
+
+ return ret;
+}
+
+static int pmc_read_data(struct device *dev, int id, u8 *value, u16 timeout)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ if (WAIT_OBF(dev, id, timeout))
+ return -ETIME;
+
+ ret = regmap_read(eio->map, eio->pmc[id].data, &val);
+ if (ret)
+ dev_err(dev, "Error PMC read %X\n", eio->pmc[id].data);
+ else
+ *value = (u8)(val & 0xFF);
+
+ return ret;
+}
+
+static int pmc_read_status(struct device *dev, int id)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ unsigned int val;
+
+ if (regmap_read(eio->map, eio->pmc[id].status, &val)) {
+ dev_err(dev, "Error PMC read %X\n",
+ eio->pmc[id].status);
+ return 0;
+ }
+
+ return val;
+}
+
+static void pmc_clear(struct device *dev, int id)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ unsigned int val;
+
+ /* Check if input buffer blocked */
+ if ((pmc_read_status(dev, id) & EIO_PMC_STATUS_IBF) == 0)
+ return;
+
+ /* Read out previous garbage */
+ if (regmap_read(eio->map, eio->pmc[id].data, &val))
+ dev_err(dev, "Error pmc clear\n");
+
+ usleep_range(10, 100);
+}
+
+int eio_core_pmc_wait(struct device *dev, int id,
+ enum eio_pmc_wait wait, uint max_duration)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ uint val;
+ int new_timeout = max_duration ? max_duration : timeout;
+
+ if (new_timeout < TIMEOUT_MIN || new_timeout > TIMEOUT_MAX) {
+ dev_err(dev,
+ "Error timeout value: %dus. Timeout value should between %d and %ld\n",
+ new_timeout, TIMEOUT_MIN, TIMEOUT_MAX);
+ return -ETIME;
+ }
+
+ if (wait == PMC_WAIT_INPUT)
+ return regmap_read_poll_timeout(eio->map, eio->pmc[id].status,
+ val, (val & EIO_PMC_STATUS_IBF) == 0,
+ SLEEP_MAX, new_timeout);
+ return regmap_read_poll_timeout(eio->map,
+ eio->pmc[id].status, val,
+ (val & EIO_PMC_STATUS_OBF) != 0,
+ SLEEP_MAX, new_timeout);
+}
+EXPORT_SYMBOL_GPL(eio_core_pmc_wait);
+
+int eio_core_pmc_operation(struct device *dev, struct pmc_op *op)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ u8 i;
+ int ret;
+ bool read_cmd = op->cmd & EIO_FLAG_PMC_READ;
+ ktime_t t = ktime_get();
+
+ mutex_lock(&eio->mutex);
+
+ pmc_clear(dev, op->chip);
+
+ ret = pmc_write_cmd(dev, op->chip, op->cmd, op->timeout);
+ if (ret)
+ goto err;
+
+ ret = pmc_write_data(dev, op->chip, op->control, op->timeout);
+ if (ret)
+ goto err;
+
+ ret = pmc_write_data(dev, op->chip, op->device_id, op->timeout);
+ if (ret)
+ goto err;
+
+ ret = pmc_write_data(dev, op->chip, op->size, op->timeout);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < op->size; i++) {
+ if (read_cmd)
+ ret = pmc_read_data(dev, op->chip, &op->payload[i],
+ op->timeout);
+ else
+ ret = pmc_write_data(dev, op->chip, op->payload[i],
+ op->timeout);
+
+ if (ret)
+ goto err;
+ }
+
+ mutex_unlock(&eio->mutex);
+
+ return 0;
+
+err:
+ mutex_unlock(&eio->mutex);
+
+ dev_err(dev, "PMC error duration:%lldus",
+ ktime_to_us(ktime_sub(ktime_get(), t)));
+ dev_err(dev,
+ ".cmd=0x%02X, .ctrl=0x%02X .id=0x%02X, .size=0x%02X .data=0x%02X%02X",
+ op->cmd, op->control, op->device_id, op->size, op->payload[0],
+ op->payload[1]);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(eio_core_pmc_operation);
+
+static int get_pmc_port(struct device *dev, int id,
+ struct eio_dev_port *port)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ struct _pmc_port *pmc = &eio->pmc[id];
+
+ eio_pnp_enter(dev, port);
+
+ /* Switch to PMC device page */
+ eio_pnp_write(dev, port, EIO_LDN, EIO_LDN_PMC1);
+
+ /* Active this device */
+ eio_pnp_write(dev, port, EIO_LDAR, EIO_LDAR_LDACT);
+
+ /* Get PMC cmd and data port */
+ pmc->data = eio_pnp_read(dev, port, EIO_IOBA0H) << 8;
+ pmc->data |= eio_pnp_read(dev, port, EIO_IOBA0L);
+ pmc->cmd = eio_pnp_read(dev, port, EIO_IOBA1H) << 8;
+ pmc->cmd |= eio_pnp_read(dev, port, EIO_IOBA1L);
+
+ /* Disable IRQ */
+ eio_pnp_write(dev, port, EIO_IRQCTRL, 0);
+
+ eio_pnp_leave(dev, port);
+
+ /* Make sure IO ports are not occupied */
+ if (!devm_request_region(dev, pmc->data, 2, KBUILD_MODNAME)) {
+ dev_err(dev, "Request region %X error\n", pmc->data);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int eio_init(struct device *dev)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ u16 chip_id = 0;
+ u8 tmp = 0;
+ int chip = 0;
+ int ret = -ENOMEM;
+
+ for (chip = 0; chip < ARRAY_SIZE(pnp_port); chip++) {
+ struct eio_dev_port *port = pnp_port + chip;
+
+ if (!devm_request_region(dev, pnp_port[chip].idx_port,
+ pnp_port[chip].data_port -
+ pnp_port[chip].idx_port,
+ KBUILD_MODNAME))
+ continue;
+
+ eio_pnp_enter(dev, port);
+
+ chip_id = eio_pnp_read(dev, port, EIO_CHIPID1) << 8;
+ chip_id |= eio_pnp_read(dev, port, EIO_CHIPID2);
+
+ if (chip_id != EIO200_CHIPID && chip_id != EIO201_211_CHIPID)
+ continue;
+
+ /* Turn on the enable flag */
+ tmp = eio_pnp_read(dev, port, EIO_SIOCTRL);
+ tmp |= EIO_SIOCTRL_SIOEN;
+
+ eio_pnp_write(dev, port, EIO_SIOCTRL, tmp);
+
+ eio_pnp_leave(dev, port);
+
+ ret = get_pmc_port(dev, chip, port);
+ if (ret)
+ return ret;
+
+ if (chip == 0)
+ eio->flag |= EIO_F_CHIP_EXIST;
+ else
+ eio->flag |= EIO_F_SUB_CHIP_EXIST;
+ }
+
+ return ret;
+}
+
+static uint8_t acpiram_access(struct device *dev, uint8_t offset)
+{
+ u8 val;
+ int ret;
+ int timeout = 0;
+ struct eio_dev *eio = dev_get_drvdata(dev);
+
+ /* We only store information on primary EC */
+ int chip = 0;
+
+ mutex_lock(&eio->mutex);
+
+ pmc_clear(dev, chip);
+
+ ret = pmc_write_cmd(dev, chip, EIO_PMC_CMD_ACPIRAM_READ, timeout);
+ if (ret)
+ goto err;
+
+ ret = pmc_write_data(dev, chip, offset, timeout);
+ if (ret)
+ goto err;
+
+ ret = pmc_write_data(dev, chip, sizeof(val), timeout);
+ if (ret)
+ goto err;
+
+ ret = pmc_read_data(dev, chip, &val, timeout);
+ if (ret)
+ goto err;
+
+err:
+ mutex_unlock(&eio->mutex);
+ return ret ? 0 : val;
+}
+
+static int firmware_code_base(struct device *dev)
+{
+ struct eio_dev *eio = dev_get_drvdata(dev);
+ u8 ic_vendor, ic_code, code_base;
+
+ ic_vendor = acpiram_access(dev, EIO_ACPIRAM_ICVENDOR);
+ ic_code = acpiram_access(dev, EIO_ACPIRAM_ICCODE);
+ code_base = acpiram_access(dev, EIO_ACPIRAM_CODEBASE);
+
+ if (ic_vendor != 'R')
+ return -ENODEV;
+
+ if (ic_code != EIO200_ICCODE && ic_code != EIO201_ICCODE &&
+ ic_code != EIO211_ICCODE)
+ goto err;
+
+ if (code_base == EIO_ACPIRAM_CODEBASE_NEW) {
+ eio->flag |= EIO_F_NEW_CODE_BASE;
+ return 0;
+ }
+
+ if (code_base == 0 &&
+ (ic_code != EIO201_ICCODE && ic_code != EIO211_ICCODE)) {
+ dev_info(dev, "Old code base not supported, yet.");
+ return -ENODEV;
+ }
+
+err:
+ /* Codebase error. This should only happen on firmware error. */
+ dev_err(dev,
+ "Codebase check fail: vendor: 0x%X, code: 0x%X, base: 0x%X\n",
+ ic_vendor, ic_code, code_base);
+ return -ENODEV;
+}
+
+static int eio_probe(struct device *dev, unsigned int id)
+{
+ int ret = 0;
+ struct eio_dev *eio;
+
+ eio = devm_kzalloc(dev, sizeof(*eio), GFP_KERNEL);
+ if (!eio)
+ return -ENOMEM;
+
+ eio->dev = dev;
+ mutex_init(&eio->mutex);
+
+ eio->iomem = devm_ioport_map(dev, 0, EIO_SUB_PNP_DATA + 1);
+ if (IS_ERR(eio->iomem))
+ return PTR_ERR(eio->iomem);
+
+ eio->map = devm_regmap_init_mmio(dev, eio->iomem, &pnp_regmap_config);
+ if (IS_ERR(eio->map))
+ return PTR_ERR(eio->map);
+
+ /* publish instance for subdrivers (dev_get_drvdata(dev->parent)) */
+ dev_set_drvdata(dev, eio);
+
+ if (eio_init(dev)) {
+ dev_dbg(dev, "No device found\n");
+ return -ENODEV;
+ }
+
+ ret = firmware_code_base(dev);
+ if (ret) {
+ dev_err(dev, "Chip code base check fail\n");
+ return ret; /* keep helper's return (e.g., -EIO) */
+ }
+
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ mfd_devs, ARRAY_SIZE(mfd_devs),
+ NULL, 0, NULL);
+ if (ret)
+ dev_err(dev, "Cannot register child devices (error = %d)\n", ret);
+
+ dev_dbg(dev, "Module insert completed\n");
+ return 0;
+}
+
+static struct isa_driver eio_driver = {
+ .probe = eio_probe,
+
+ .driver = {
+ .name = "eio_core",
+ .dev_groups = pmc_groups,
+ },
+};
+module_isa_driver(eio_driver, 1);
+
+MODULE_AUTHOR("Wenkai Chung <wenkai.chung@advantech.com.tw>");
+MODULE_AUTHOR("Ramiro Oliveira <ramiro.oliveira@advantech.com>");
+MODULE_DESCRIPTION("Advantech EIO series EC core driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/eio.h b/include/linux/mfd/eio.h
new file mode 100644
index 000000000000..b87614274201
--- /dev/null
+++ b/include/linux/mfd/eio.h
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Header for the Advantech EIO core driver and its sub-drivers
+ *
+ * Copyright (C) 2025 Advantech Co., Ltd.
+ */
+
+#ifndef _MFD_EIO_H_
+#define _MFD_EIO_H_
+#include <linux/io.h>
+#include <linux/regmap.h>
+
+/* Definition */
+#define EIO_CHIPID1 0x20
+#define EIO_CHIPID2 0x21
+#define EIO_CHIPVER 0x22
+#define EIO_SIOCTRL 0x23
+#define EIO_SIOCTRL_SIOEN BIT(0)
+#define EIO_SIOCTRL_SWRST BIT(1)
+#define EIO_IRQCTRL 0x70
+#define EIO200_CHIPID 0x9610
+#define EIO201_211_CHIPID 0x9620
+#define EIO200_ICCODE 0x10
+#define EIO201_ICCODE 0x20
+#define EIO211_ICCODE 0x21
+
+/* LPC PNP */
+#define EIO_PNP_INDEX 0x299
+#define EIO_PNP_DATA 0x29A
+#define EIO_SUB_PNP_INDEX 0x499
+#define EIO_SUB_PNP_DATA 0x49A
+#define EIO_EXT_MODE_ENTER 0x87
+#define EIO_EXT_MODE_EXIT 0xAA
+
+/* LPC LDN */
+#define EIO_LDN 0x07
+#define EIO_LDN_PMC0 0x0C
+#define EIO_LDN_PMC1 0x0D
+
+/* PMC registers */
+#define EIO_PMC_STATUS_IBF BIT(1)
+#define EIO_PMC_STATUS_OBF BIT(0)
+#define EIO_LDAR 0x30
+#define EIO_LDAR_LDACT BIT(0)
+#define EIO_IOBA0H 0x60
+#define EIO_IOBA0L 0x61
+#define EIO_IOBA1H 0x62
+#define EIO_IOBA1L 0x63
+#define EIO_FLAG_PMC_READ BIT(0)
+
+/* PMC command list */
+#define EIO_PMC_CMD_ACPIRAM_READ 0x31
+#define EIO_PMC_CMD_CFG_SAVE 0x56
+
+/* OLD PMC */
+#define EIO_PMC_NO_INDEX 0xFF
+
+/* ACPI RAM Address Table */
+#define EIO_ACPIRAM_VERSIONSECTION (0xFA)
+#define EIO_ACPIRAM_ICVENDOR (EIO_ACPIRAM_VERSIONSECTION + 0x00)
+#define EIO_ACPIRAM_ICCODE (EIO_ACPIRAM_VERSIONSECTION + 0x01)
+#define EIO_ACPIRAM_CODEBASE (EIO_ACPIRAM_VERSIONSECTION + 0x02)
+
+#define EIO_ACPIRAM_CODEBASE_NEW BIT(7)
+
+/* Firmware */
+#define EIO_F_SUB_NEW_CODE_BASE BIT(6)
+#define EIO_F_SUB_CHANGED BIT(7)
+#define EIO_F_NEW_CODE_BASE BIT(8)
+#define EIO_F_CHANGED BIT(9)
+#define EIO_F_SUB_CHIP_EXIST BIT(30)
+#define EIO_F_CHIP_EXIST BIT(31)
+
+/* Others */
+#define EIO_EC_NUM 2
+
+struct _pmc_port {
+ union {
+ u16 cmd;
+ u16 status;
+ };
+ u16 data;
+};
+
+struct pmc_op {
+ u8 cmd;
+ u8 control;
+ u8 device_id;
+ u8 size;
+ u8 *payload;
+ u8 chip;
+ u16 timeout;
+};
+
+enum eio_rw_operation {
+ OPERATION_READ,
+ OPERATION_WRITE,
+};
+
+struct eio_dev {
+ struct device *dev;
+ struct regmap *map;
+ void __iomem *iomem;
+ struct mutex mutex; /* Protects PMC command access */
+ struct _pmc_port pmc[EIO_EC_NUM];
+ u32 flag;
+};
+
+int eio_core_pmc_operation(struct device *dev, struct pmc_op *operation);
+
+enum eio_pmc_wait {
+ PMC_WAIT_INPUT,
+ PMC_WAIT_OUTPUT,
+};
+
+int eio_core_pmc_wait(struct device *dev, int id, enum eio_pmc_wait wait,
+ uint timeout);
+
+#define WAIT_IBF(dev, id, timeout) eio_core_pmc_wait(dev, id, PMC_WAIT_INPUT, timeout)
+#define WAIT_OBF(dev, id, timeout) eio_core_pmc_wait(dev, id, PMC_WAIT_OUTPUT, timeout)
+
+#ifdef pr_fmt
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#endif
+
+#endif
--
2.43.0
^ permalink raw reply related
* [PATCH 2/8] Add Advantech EIO GPIO driver
From: Ramiro Oliveira @ 2025-12-12 16:40 UTC (permalink / raw)
To: Lee Jones, Linus Walleij, Bartosz Golaszewski, Guenter Roeck,
Andi Shyti, Daniel Thompson, Jingoo Han, Helge Deller,
Wim Van Sebroeck, Rafael J. Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba
Cc: linux-kernel, linux-gpio, linux-hwmon, linux-i2c, dri-devel,
linux-fbdev, linux-watchdog, linux-pm, Wenkai Chung,
Francisco Aragon-Trivino, Hongzhi Wang, Mikhail Tsukerman,
Thomas Kastner, Ramiro Oliveira
In-Reply-To: <20251212-upstream-v1-v1-0-d50d40ec8d8a@advantech.com>
This driver controls the GPIO component of the Advantech EIO chip.
Signed-off-by: Ramiro Oliveira <ramiro.oliveira@advantech.com>
---
MAINTAINERS | 1 +
drivers/gpio/Kconfig | 6 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-eio.c | 273 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 281 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index bd9279796c2f..359d4a13f212 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -619,6 +619,7 @@ F: drivers/platform/x86/adv_swbutton.c
ADVANTECH EIO DRIVER
M: Ramiro Oliveira <ramiro.oliveira@advantech.com>
S: Maintained
+F: drivers/gpio/gpio-eio.c
F: drivers/mfd/eio_core.c
F: include/linux/mfd/eio.h
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index bd185482a7fd..628a914842bd 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -277,6 +277,12 @@ config GPIO_DWAPB
Say Y or M here to build support for the Synopsys DesignWare APB
GPIO block.
+config GPIO_EIO
+ tristate "Advantech EIO GPIO"
+ depends on MFD_EIO
+ help
+ Say Y or M to build support for Advantech EIO GPIO block.
+
config GPIO_EIC_SPRD
tristate "Spreadtrum EIC support"
depends on ARCH_SPRD || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 2421a8fd3733..ba3883d5e4a0 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DS4520) += gpio-ds4520.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
+obj-$(CONFIG_GPIO_EIO) += gpio-eio.o
obj-$(CONFIG_GPIO_ELKHARTLAKE) += gpio-elkhartlake.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EN7523) += gpio-en7523.o
diff --git a/drivers/gpio/gpio-eio.c b/drivers/gpio/gpio-eio.c
new file mode 100644
index 000000000000..50f66a325e8f
--- /dev/null
+++ b/drivers/gpio/gpio-eio.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * GPIO driver for Advantech EIO Embedded controller.
+ *
+ * Copyright (C) 2025 Advantech Corporation. All rights reserved.
+ */
+
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/eio.h>
+#include <linux/module.h>
+
+#define GPIO_MAX_PINS 48
+#define GPIO_WRITE 0x18
+#define GPIO_READ 0x19
+
+struct eio_gpio_dev {
+ u64 avail;
+ int max;
+ struct gpio_chip chip;
+ struct device *dev;
+};
+
+struct {
+ int size;
+ bool write;
+} ctrl_para[] = {
+ { 0x01, false }, { 0x00, false }, { 0x00, false }, { 0x02, false },
+ { 0x01, false }, { 0x00, false }, { 0x00, false }, { 0x00, false },
+ { 0x00, false }, { 0x00, false }, { 0x00, false }, { 0x00, false },
+ { 0x00, false }, { 0x00, false }, { 0x00, false }, { 0x00, false },
+ { 0x01, true }, { 0x01, true }, { 0x02, true }, { 0x02, true },
+ { 0x02, false }, { 0x10, false }
+};
+
+enum {
+ GPIO_STATUS = 0,
+ GPIO_GROUP_AVAIL = 3,
+ GPIO_ERROR = 0x04,
+ GPIO_PIN_DIR = 0x10,
+ GPIO_PIN_LEVEL = 0x11,
+ GPIO_GROUP_DIR = 0x12,
+ GPIO_GROUP_LEVEL = 0x13,
+ GPIO_MAPPING = 0x14,
+ GPIO_NAME = 0x15
+} gpio_ctrl;
+
+struct {
+ int group;
+ int port;
+} group_map[] = {
+ { 0, 0 }, { 0, 1 },
+ { 1, 0 }, { 1, 1 },
+ { 2, 0 }, { 2, 1 },
+ { 3, 0 }, { 3, 1 },
+ { 3, 2 }, { 3, 3 },
+ { 3, 4 }, { 3, 5 },
+ { 3, 6 }, { 3, 7 }
+};
+
+static int timeout;
+module_param(timeout, int, 0444);
+MODULE_PARM_DESC(timeout, "Set PMC command timeout value.\n");
+
+static int pmc_write(struct device *mfd_dev, u8 ctrl, u8 dev_id, void *data)
+{
+ struct pmc_op op = {
+ .cmd = GPIO_WRITE,
+ .control = ctrl,
+ .device_id = dev_id,
+ .payload = (u8 *)data,
+ .timeout = timeout,
+ };
+
+ if (ctrl > ARRAY_SIZE(ctrl_para))
+ return -ENOMEM;
+
+ if (!ctrl_para[ctrl].write)
+ return -EINVAL;
+
+ op.size = ctrl_para[ctrl].size;
+
+ return eio_core_pmc_operation(mfd_dev, &op);
+}
+
+static int pmc_read(struct device *mfd_dev, u8 ctrl, u8 dev_id, void *data)
+{
+ struct pmc_op op = {
+ .cmd = GPIO_READ,
+ .control = ctrl,
+ .device_id = dev_id,
+ .payload = (u8 *)data,
+ .timeout = timeout,
+ };
+
+ if (ctrl > ARRAY_SIZE(ctrl_para))
+ return -ENOMEM;
+
+ op.size = ctrl_para[ctrl].size;
+
+ return eio_core_pmc_operation(mfd_dev, &op);
+}
+
+static int get_dir(struct gpio_chip *chip, unsigned int offset)
+{
+ u8 dir;
+ int ret;
+
+ ret = pmc_read(chip->parent, GPIO_PIN_DIR, offset, &dir);
+ if (ret)
+ return ret;
+
+ return dir ? 0 : 1;
+}
+
+static int dir_input(struct gpio_chip *chip, unsigned int offset)
+{
+ u8 dir = 0;
+
+ return pmc_write(chip->parent, GPIO_PIN_DIR, offset, &dir);
+}
+
+static int dir_output(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ u8 dir = 1;
+ u8 val = value;
+
+ pmc_write(chip->parent, GPIO_PIN_DIR, offset, &dir);
+
+ return pmc_write(chip->parent, GPIO_PIN_LEVEL, offset, &val);
+}
+
+static int gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ u8 level;
+ int ret;
+
+ ret = pmc_read(chip->parent, GPIO_PIN_LEVEL, offset, &level);
+ if (ret)
+ return ret;
+
+ return level;
+}
+
+static int gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ u8 val = value;
+
+ pmc_write(chip->parent, GPIO_PIN_LEVEL, offset, &val);
+
+ return 0;
+}
+
+static int check_support(struct device *dev)
+{
+ u8 data;
+ int ret;
+
+ ret = pmc_read(dev, GPIO_STATUS, 0, &data);
+ if (!ret)
+ return ret;
+
+ if ((data & 0x01) == 0)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int check_pin(struct device *dev, int pin)
+{
+ int ret;
+ int group, bit;
+ u16 data;
+
+ /* Get pin mapping */
+ ret = pmc_read(dev, GPIO_MAPPING, pin, &data);
+ if (ret)
+ return ret;
+
+ if ((data & 0xFF) > ARRAY_SIZE(group_map))
+ return -EINVAL;
+
+ group = group_map[data & 0xFF].group;
+ bit = data >> 8;
+
+ /* Check mapped pin */
+ ret = pmc_read(dev, GPIO_GROUP_AVAIL, group, &data);
+ if (ret)
+ return ret;
+
+ return data & BIT(bit) ? 0 : -EOPNOTSUPP;
+}
+
+static int gpio_init(struct device *mfd, struct eio_gpio_dev *eio_gpio)
+{
+ int ret;
+ int i;
+ char str[GPIO_MAX_PINS + 1];
+
+ memset(str, 0x30, sizeof(str));
+
+ ret = check_support(mfd);
+ if (ret) {
+ dev_err(eio_gpio->dev, "GPIO not supported (%d)\n", ret);
+ return ret;
+ }
+
+ eio_gpio->avail = 0;
+
+ for (i = 0 ; i < GPIO_MAX_PINS ; i++) {
+ ret = check_pin(mfd, i);
+ if (ret)
+ continue;
+
+ eio_gpio->avail |= BIT(i);
+ eio_gpio->max = i + 1;
+ str[GPIO_MAX_PINS - i] = '1';
+ }
+
+ dev_info(eio_gpio->dev, "GPIO pins=%s\n", str);
+
+ return eio_gpio->max ? 0 : -EOPNOTSUPP;
+}
+
+static const struct gpio_chip eio_gpio_chip = {
+ .label = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .direction_input = dir_input,
+ .get = gpio_get,
+ .direction_output = dir_output,
+ .set = gpio_set,
+ .get_direction = get_dir,
+ .base = -1,
+ .can_sleep = true,
+};
+
+static int gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct eio_gpio_dev *eio_gpio;
+ struct eio_dev *eio_dev = dev_get_drvdata(dev->parent);
+
+ if (!eio_dev) {
+ dev_err(dev, "Error contact eio_core\n");
+ return -ENODEV;
+ }
+
+ eio_gpio = devm_kzalloc(dev, sizeof(*eio_gpio), GFP_KERNEL);
+ eio_gpio->dev = dev;
+
+ if (gpio_init(dev->parent, eio_gpio))
+ return -EIO;
+
+ eio_gpio->chip = eio_gpio_chip;
+ eio_gpio->chip.parent = dev->parent;
+ eio_gpio->chip.ngpio = eio_gpio->max;
+
+ return devm_gpiochip_add_data(dev, &eio_gpio->chip, eio_gpio);
+}
+
+static struct platform_driver gpio_driver = {
+ .probe = gpio_probe,
+ .driver = { .name = KBUILD_MODNAME, },
+};
+
+module_platform_driver(gpio_driver);
+
+MODULE_AUTHOR("Wenkai Chung <wenkai.chung@advantech.com.tw>");
+MODULE_AUTHOR("Ramiro Oliveira <ramiro.oliveira@advantech.com>");
+MODULE_DESCRIPTION("GPIO driver for Advantech EIO embedded controller");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH 3/8] Add Advantech EIO Hardware Monitor driver
From: Ramiro Oliveira @ 2025-12-12 16:40 UTC (permalink / raw)
To: Lee Jones, Linus Walleij, Bartosz Golaszewski, Guenter Roeck,
Andi Shyti, Daniel Thompson, Jingoo Han, Helge Deller,
Wim Van Sebroeck, Rafael J. Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba
Cc: linux-kernel, linux-gpio, linux-hwmon, linux-i2c, dri-devel,
linux-fbdev, linux-watchdog, linux-pm, Wenkai Chung,
Francisco Aragon-Trivino, Hongzhi Wang, Mikhail Tsukerman,
Thomas Kastner, Ramiro Oliveira
In-Reply-To: <20251212-upstream-v1-v1-0-d50d40ec8d8a@advantech.com>
This driver controls the Hardware Monitor block of the Advantech EIO chip.
Signed-off-by: Ramiro Oliveira <ramiro.oliveira@advantech.com>
---
MAINTAINERS | 1 +
drivers/hwmon/Kconfig | 10 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/eio-hwmon.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 356 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 359d4a13f212..fdd39b152f41 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -620,6 +620,7 @@ ADVANTECH EIO DRIVER
M: Ramiro Oliveira <ramiro.oliveira@advantech.com>
S: Maintained
F: drivers/gpio/gpio-eio.c
+F: drivers/hwmon/eio-hwmon.c
F: drivers/mfd/eio_core.c
F: include/linux/mfd/eio.h
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 157678b821fc..08993b993596 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -2043,6 +2043,16 @@ config SENSORS_DME1737
This driver can also be built as a module. If so, the module
will be called dme1737.
+config SENSORS_EIO
+ tristate "Advantech EIO HWMON"
+ depends on MFD_EIO
+ help
+ If you say yes here you get support for the Advantech EIO
+ temperature, voltage and fan speed monitoring block.
+
+ This driver can also be built as a module. If so, the module
+ will be called eio-hwmon
+
config SENSORS_EMC1403
tristate "SMSC EMC1403/23 thermal sensor"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index eade8e3b1bde..e69f03b41fae 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DRIVETEMP) += drivetemp.o
obj-$(CONFIG_SENSORS_DS620) += ds620.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
+obj-$(CONFIG_SENSORS_EIO) += eio-hwmon.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
obj-$(CONFIG_SENSORS_EMC2305) += emc2305.o
diff --git a/drivers/hwmon/eio-hwmon.c b/drivers/hwmon/eio-hwmon.c
new file mode 100644
index 000000000000..164591aa31a7
--- /dev/null
+++ b/drivers/hwmon/eio-hwmon.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * GPIO driver for Advantech EIO embedded controller.
+ *
+ * Copyright (C) 2025 Advantech Corporation. All rights reserved.
+ */
+
+#include <linux/errno.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/eio.h>
+#include <linux/module.h>
+
+#define MAX_DEV 128
+#define MAX_NAME 32
+
+static uint timeout;
+module_param(timeout, uint, 0444);
+MODULE_PARM_DESC(timeout,
+ "Default pmc command timeout in micro-seconds.\n");
+
+struct eio_hwmon_dev {
+ struct device *mfd;
+};
+
+enum _sen_type {
+ NONE,
+ VOLTAGE,
+ CURRENT,
+ TEMP,
+ PWM,
+ TACHO,
+ FAN,
+ CASEOPEN,
+};
+
+struct eio_key {
+ enum _sen_type type;
+ u8 chan;
+ u8 item;
+ u8 label_idx;
+};
+
+struct eio_attr {
+ struct sensor_device_attribute sda;
+ struct eio_key key;
+};
+
+static struct {
+ u8 cmd;
+ u8 max;
+ signed int shift;
+ char name[32];
+ u8 ctrl[16];
+ u16 multi[16];
+ char item[16][32];
+ char labels[32][32];
+
+} sen_info[] = {
+ { 0x00, 0, 0, "none" },
+ { 0x12, 8, 0, "in",
+ { 0xFF, 0x10, 0x11, 0x12 },
+ { 1, 10, 10, 10 },
+ { "label", "input", "max", "min" },
+ { "5V", "5Vs5", "12V", "12Vs5",
+ "3V3", "3V3", "5Vsb", "3Vsb",
+ "Vcmos", "Vbat", "Vdc", "Vstb",
+ "Vcore_a", "Vcore_b", "", "",
+ "Voem0", "Voem1", "Voem2", "Voem3"
+ },
+ },
+ { 0x1a, 2, 0, "curr",
+ { 0xFF, 0x10, 0x11, 0x12 },
+ { 1, 10, 10, 10 },
+ { "label", "input", "max", "min" },
+ { "dc", "oem0" },
+ },
+ { 0x10, 4, -2731, "temp",
+ { 0xFF, 0x10, 0x11, 0x12, 0x21, 0x41 },
+ { 1, 100, 100, 100, 100, 100 },
+ { "label", "input", "max", "min", "crit", "emergency" },
+ { "cpu0", "cpu1", "cpu2", "cpu3",
+ "sys0", "sys1", "sys2", "sys3",
+ "aux0", "aux1", "aux2", "aux3",
+ "dimm0", "dimm1", "dimm2", "dimm3",
+ "pch", "gpu", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "oem0", "oem1", "oem", "oem3" },
+ },
+ { 0x14, 0, 0, "pwm",
+ { 0xFF, 0x11, 0x12 },
+ { 1, 1, 1 },
+ { "label", "polarity", "freq" },
+ { "pwm0", "pwm0", "pwm0", "pwm0" },
+ },
+ { 0x16, 2, 0, "tacho",
+ { 0xFF, 0x10 },
+ { 1, 1 },
+ { "label", "input"},
+ { "cpu0", "cpu1", "cpu2", "cpu3",
+ "sys0", "sys1", "sys2", "sys3",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "",
+ "oem0", "oem1", "oem2", "oem3"
+ },
+ },
+ { 0x24, 4, 0, "fan",
+ { 0xFF, 0x1A },
+ { 1, 1 },
+ { "label", "input"},
+ { "cpu0", "cpu1", "cpu2", "cpu3",
+ "sys0", "sys1", "sys2", "sys3",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "",
+ "oem0", "oem1", "oem2", "oem3",
+ },
+ },
+ { 0x28, 1, 0, "intrusion",
+ { 0xFF, 0x02 },
+ { 1, 1 },
+ { "label", "input" },
+ { "case_open" }
+ }
+};
+
+static struct {
+ enum _sen_type type;
+ u8 ctrl;
+ int size;
+ bool write;
+
+} ctrl_para[] = {
+ { NONE, 0x00, 0, false },
+
+ { VOLTAGE, 0x00, 1, false }, { VOLTAGE, 0x01, 1, false },
+ { VOLTAGE, 0x10, 2, false }, { VOLTAGE, 0x11, 2, false },
+ { VOLTAGE, 0x12, 2, false },
+
+ { CURRENT, 0x00, 1, false }, { CURRENT, 0x01, 1, false },
+ { CURRENT, 0x10, 2, false }, { CURRENT, 0x11, 2, false },
+ { CURRENT, 0x12, 2, false },
+
+ { TEMP, 0x00, 2, false }, { TEMP, 0x01, 1, false },
+ { TEMP, 0x04, 1, false }, { TEMP, 0x10, 2, false },
+ { TEMP, 0x11, 2, false }, { TEMP, 0x12, 2, false },
+ { TEMP, 0x21, 2, false }, { TEMP, 0x41, 2, false },
+
+ { PWM, 0x00, 1, false }, { PWM, 0x10, 1, true },
+ { PWM, 0x11, 1, true }, { PWM, 0x12, 4, true },
+
+ { TACHO, 0x00, 1, false }, { TACHO, 0x01, 1, false },
+ { TACHO, 0x10, 4, true },
+
+ { FAN, 0x00, 1, false }, { FAN, 0x01, 1, false },
+ { FAN, 0x03, 1, true }, { FAN, 0x1A, 2, false },
+
+ { CASEOPEN, 0x00, 1, false }, { CASEOPEN, 0x02, 1, true },
+};
+
+static int para_idx(enum _sen_type type, u8 ctrl)
+{
+ int i;
+
+ for (i = 1 ; i < ARRAY_SIZE(ctrl_para) ; i++)
+ if (type == ctrl_para[i].type &&
+ ctrl == ctrl_para[i].ctrl)
+ return i;
+
+ return 0;
+}
+
+static int pmc_read(struct device *mfd, enum _sen_type type, u8 dev_id, u8 ctrl, void *data)
+{
+ int idx = para_idx(type, ctrl);
+ int ret = 0;
+
+ if (idx == 0)
+ return -EINVAL;
+
+ if (WARN_ON(!data))
+ return -EINVAL;
+
+ struct pmc_op op = {
+ .cmd = sen_info[type].cmd | EIO_FLAG_PMC_READ,
+ .control = ctrl,
+ .device_id = dev_id,
+ .size = ctrl_para[idx].size,
+ .payload = (u8 *)data,
+ .timeout = timeout,
+ };
+
+ ret = eio_core_pmc_operation(mfd, &op);
+ return ret;
+}
+
+static ssize_t eio_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct eio_hwmon_dev *eio_hwmon = dev_get_drvdata(dev);
+ struct eio_attr *eio_attr =
+ container_of(attr, struct eio_attr, sda.dev_attr);
+ const struct eio_key *eio_key = &eio_attr->key;
+ int ret;
+ u8 data[2];
+ u32 temp_val;
+ signed int final_val;
+
+ switch (eio_key->item) {
+ case 0:
+ return sysfs_emit(buf, "%s\n",
+ sen_info[eio_key->type].labels[eio_key->label_idx]);
+
+ default:
+ ret = pmc_read(eio_hwmon->mfd, eio_key->type, eio_key->chan,
+ sen_info[eio_key->type].ctrl[eio_key->item],
+ &data);
+ if (ret)
+ return ret;
+
+ temp_val = data[0] | data[1] << 8;
+
+ final_val = (signed int)temp_val + (signed int)(sen_info[eio_key->type].shift);
+ final_val = final_val * (signed int)sen_info[eio_key->type].multi[eio_key->item];
+
+ return sysfs_emit(buf, "%d\n", final_val);
+ }
+
+ return -EINVAL;
+}
+
+static char devname[MAX_DEV][MAX_NAME];
+static struct eio_attr devattrs[MAX_DEV];
+static struct attribute *attrs[MAX_DEV];
+
+static struct attribute_group group = {
+ .attrs = attrs,
+};
+
+static const struct attribute_group *groups[] = {
+ &group,
+ NULL
+};
+
+static int hwmon_init(struct device *mfd, struct eio_hwmon_dev *eio_hwmon)
+{
+ enum _sen_type type;
+ u8 i, j, data[16];
+ int sum = 0;
+ int ret;
+
+ for (type = VOLTAGE ; type <= CASEOPEN ; type++) {
+ int cnt = 1;
+
+ for (i = 0 ; i < sen_info[type].max ; i++) {
+ if (pmc_read(mfd, type, i, 0x00, data) ||
+ (data[0] & 0x01) == 0)
+ continue;
+
+ memset(data, 0, sizeof(data));
+ ret = pmc_read(mfd, type, i, 0x01, data);
+ if (ret != 0 && ret != -EINVAL) {
+ dev_info(mfd, "read type id error\n");
+ continue;
+ }
+
+ for (j = 0 ; j < ARRAY_SIZE(sen_info->item) ; j++) {
+ struct eio_attr *eio_attr;
+
+ if (sen_info[type].item[j][0] == 0)
+ continue;
+
+ eio_attr = &devattrs[sum];
+
+ eio_attr->key.type = type;
+ eio_attr->key.chan = i;
+ eio_attr->key.item = j;
+ eio_attr->key.label_idx = data[0];
+
+ snprintf(devname[sum], sizeof(devname[sum]),
+ "%s%d_%s", sen_info[type].name, cnt,
+ sen_info[type].item[j]);
+
+ eio_attr->sda.dev_attr.attr.name = devname[sum];
+ eio_attr->sda.dev_attr.attr.mode = 0444;
+ eio_attr->sda.dev_attr.show = eio_show;
+
+ attrs[sum] = &eio_attr->sda.dev_attr.attr;
+
+ if (++sum >= MAX_DEV)
+ break;
+ }
+ cnt++;
+ }
+ }
+
+ return sum;
+}
+
+static int hwmon_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct eio_hwmon_dev *eio_hwmon;
+ struct eio_dev *eio_dev = dev_get_drvdata(dev->parent);
+ struct device *hwmon;
+
+ if (!eio_dev) {
+ dev_err(dev, "Error contact eio_core\n");
+ return -ENODEV;
+ }
+
+ eio_hwmon = devm_kzalloc(dev, sizeof(*eio_hwmon), GFP_KERNEL);
+ if (!eio_hwmon)
+ return -ENOMEM;
+
+ eio_hwmon->mfd = dev->parent;
+ platform_set_drvdata(pdev, eio_hwmon);
+
+ if (hwmon_init(dev->parent, eio_hwmon) <= 0)
+ return -ENODEV;
+
+ hwmon = devm_hwmon_device_register_with_groups(dev, KBUILD_MODNAME,
+ eio_hwmon,
+ groups);
+ return PTR_ERR_OR_ZERO(hwmon);
+}
+
+static struct platform_driver eio_hwmon_driver = {
+ .probe = hwmon_probe,
+ .driver = {
+ .name = "eio_hwmon",
+ },
+};
+
+module_platform_driver(eio_hwmon_driver);
+
+MODULE_AUTHOR("Wenkai Chung <wenkai.chung@advantech.com.tw>");
+MODULE_AUTHOR("Ramiro Oliveira <ramiro.oliveira@advantech.com>");
+MODULE_DESCRIPTION("Hardware monitor driver for Advantech EIO embedded controller");
+MODULE_LICENSE("GPL");
+
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox