aboutsummaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2018-08-06drm/amd/display: update clk for various HDMI color depthsMikita Lipski1-0/+18
[why] When programming tonga's connector's backend we didn't take in account that HDMI's colour depth might be more than 8bpc therefore we need to add a switch statement that would adjust the pixel clock accordingly. [how] Add a switch statement updating clock by its appropriate coefficient. Signed-off-by: Mikita Lipski <[email protected]> Reviewed-by: Charlene Liu <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Cc: [email protected]
2018-08-06drm/amd/display: program display clock on cache matchDmytro Laktyushkin2-1/+5
[Why] We seem to have an issue where high enough display clock will not get set properly during S3 resume if we only call vbios once [How] Expand condition of display clock programming to happen even when cached display clock matches requested display clock Signed-off-by: Dmytro Laktyushkin <[email protected]> Reviewed-by: Tony Cheng <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: Add NULL check for enabling dp ssNicholas Kazlauskas1-1/+3
[Why] The pointer for integrated_info can be NULL which causes the system to do a null pointer deference and hang on boot. [How] Add a check to ensure that integrated_info is not null before enabling DP ss. Signed-off-by: Nicholas Kazlauskas <[email protected]> Reviewed-by: Sun peng Li <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: add vbios table check for enabling dp ssDmytro Laktyushkin4-1/+8
Signed-off-by: Dmytro Laktyushkin <[email protected]> Reviewed-by: Eric Bernstein <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: Don't share clk source between DP and HDMIMikita Lipski4-2/+26
[why] Prevent clock source sharing between HDMI and DP connectors. DP shouldn't be sharing its ref clock with phy clock, which caused an issue of older ASICS booting up with multiple diplays plugged in. [how] Add an extra check that would prevent HDMI and DP sharing clk. Signed-off-by: Mikita Lipski <[email protected]> Reviewed-by: Hersen Wu <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Cc: [email protected]
2018-08-06drm/amd/display: Fix DP HBR2 Eye Diagram Pattern on CarrizoHersen Wu3-5/+6
[why] dp hbr2 eye diagram pattern for raven asic is not stabled. workaround is to use tp4 pattern. But this should not be applied to asic before raven. [how] add new bool varilable in asic caps. for raven asic, use the workaround. for carrizo, vega, do not use workaround. Signed-off-by: Hersen Wu <[email protected]> Reviewed-by: Harry Wentland <[email protected]> Acked-by: Leo Li <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: Use calculated disp_clk_khz value for dce110Nicholas Kazlauskas2-4/+4
[Why] The calculated values for actual disp_clk_khz were ignored when notifying pplib of the new display requirements. In order to honor DFS bypass clocks from the hardware, the calculated value should be used. [How] The return value for set_dispclk is now assigned back into new_clocks and correctly carried through into dccg->clks.phyclk_khz. When notifying pplib of new display requirements dccg->clks.phyclk_khz is used instead of dce.dispclk_khz. The value of dce.dispclk_khz was never explicitly set to anything before. A 15% higher display clock value than calculated is no longer requested for dce110 since it now makes use of the calculated value. Since dce112 makes use of dce110's set_bandwidth but not its update_clocks it needs to have the value correctly carried through. Signed-off-by: Nicholas Kazlauskas <[email protected]> Reviewed-by: Harry Wentland <[email protected]> Reviewed-by: Dmytro Laktyushkin <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: Implement custom degamma lut on dcnDavid Francis4-15/+46
[Why] Custom degamma lut functions are a feature we would like to support on compatible hardware [How] In atomic check, convert from array of drm_color_lut to dc_transfer_func. On hardware commit, allow for possibility of custom degamma. Both are based on the equivalent regamma pipeline. Signed-off-by: David Francis <[email protected]> Reviewed-by: Krunoslav Kovac <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: Destroy aux_engines only onceDavid Francis1-3/+0
[Why] In the dce112 function to destroy the resource pool, engines (the aux engines) is destroyed twice. This has no ill effects but is a tad redundant. [How] Remove the redundant call Signed-off-by: David Francis <[email protected]> Reviewed-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: Read back max backlight value at bootDavid Francis1-0/+1
[Why] If there is no program explicitly setting the backlight brightness (for example, during a minimal install of linux), the hardware defaults to maximum brightness but the backlight_device defaults to 0 value. Thus, settings displays the wrong brightness value. [How] When creating the backlight device, set brightness to max Signed-off-by: David Francis <[email protected]> Reviewed-by: Harry Wentland <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: Implement backlight_ops.get_brightnessDavid Francis3-1/+17
[Why] This hook that is supposed to read the actual backlight value is used in a few places throughout the kernel to setup or force update on backlight [How] Create a dc function that calls the existing abm function, and call that function from amdgpu Signed-off-by: David Francis <[email protected]> Reviewed-by: Harry Wentland <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: DP Compliance 400.1.1 failureabdoulaye berthe1-26/+28
[Why] 400.1.1 is failing because we are not performing link training when we get an HPD pulse for the same display. This is breaking DP compliance [How] Always perform link training after HPD pulse if the detection reason is not DETECT_REASON_HPDRX. Signed-off-by: abdoulaye berthe <[email protected]> Reviewed-by: Wenjing Liu <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-06drm/amd/display: Use requested HDMI aspect ratioLeo (Sunpeng) Li1-7/+2
[Why] The DRM mode's HDMI picture aspect ratio field was never saved in dc_stream's timing struct. This causes us to mistake a new stream to have the same timings as the old, even though the user has requested a different aspect ratio. [How] Save DRM's aspect ratio field within dc_stream's timing struct. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=107153 Signed-off-by: Leo (Sunpeng) Li <[email protected]> Reviewed-by: Mikita Lipski <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Cc: [email protected]
2018-08-03drm/amd/display: Only require EDID read for HDMI and DVIHarry Wentland1-1/+2
[Why] VGA sometimes has trouble retrieving the EDID on very long cables, KVM switches, or old displays. [How] Only require EDID read for HDMI and DVI and exempt other types (DP, VGA). We currently don't support VGA but if anyone adds support in the future this might get overlooked. Signed-off-by: Harry Wentland <[email protected]> Suggested-by: Michel Dänzer <[email protected]> Acked-by: Alex Deucher <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-03drm/amd/display: Report non-DP display as disconnected without EDIDHarry Wentland1-0/+11
[Why] Some boards seem to have a problem where HPD is high on HDMI even though no display is connected. We don't want to report these as connected. DP spec still requires us to report DP displays as connected when HPD is high but we can't read the EDID in order to go to fail-safe mode. [How] If connector_signal is not DP abort detection if we can't retrieve the EDID. v2: Add Bugzilla and stable Bugzilla: https://bugs.freedesktop.org/107390 Bugzilla: https://bugs.freedesktop.org/106846 Cc: [email protected] Signed-off-by: Harry Wentland <[email protected]> Acked-by: Alex Deucher <[email protected]> Reviewed-by: Nicholas Kazlauskas <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-01drm/ttm: clean up non-x86 definitions on ttm_ttHuang Rui1-18/+7
All non-x86 definitions are moved to ttm_set_memory header, so remove it from ttm_tt.c. Reviewed-by: Christian König <[email protected]> Signed-off-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-01drm/ttm: Add ttm_set_pages_wc and ttm_set_pages_uc helperHuang Rui1-0/+22
These two helpers will be used on set page caching. Reviewed-by: Christian König <[email protected]> Signed-off-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-08-01drm/ttm: fix missed conversion of set_pages_array_ucHuang Rui1-1/+1
This patch fixed the error when do not configure CONFIG_X86, otherwise, below error will be encountered. All errors (new ones prefixed by >>): drivers/gpu/drm/ttm/ttm_page_alloc_dma.c: In function 'ttm_set_pages_caching': >> drivers/gpu/drm/ttm/ttm_page_alloc_dma.c:272:7: error: implicit declaration of function 'set_pages_array_uc'; did you mean +'ttm_set_pages_array_uc'? [-Werror=implicit-function-declaration] r = set_pages_array_uc(pages, cpages); ^~~~~~~~~~~~~~~~~~ ttm_set_pages_array_uc cc1: some warnings being treated as errors Reported-by: kbuild test robot <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu/pm: Fix potential Spectre v1Gustavo A. R. Silva1-1/+2
idx can be indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:408 amdgpu_set_pp_force_state() warn: potential spectre issue 'data.states' Fix this by sanitizing idx before using it to index data.states Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Cc: [email protected] Signed-off-by: Gustavo A. R. Silva <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amd/display: add missing void parameter to dc_create_transfer_funcColin Ian King1-1/+1
Add a missing void parameter to function dc_create_transfer_func, fixes sparse warning: warning: non-ANSI function declaration of function 'dc_create_transfer_func' Signed-off-by: Colin Ian King <[email protected]> Reviewed-by: Harry Wentland <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/radeon: Replace ttm_bo_unref with ttm_bo_putThomas Zimmermann1-3/+2
The function ttm_bo_put releases a reference to a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. A call to ttm_bo_unref takes the address of the TTM BO object's pointer and clears the pointer's value to NULL. This is not necessary in most cases and sometimes even worked around by the calling code. A call to ttm_bo_put only releases the reference without clearing the pointer. The current behaviour of cleaning the pointer is kept in the calling code, but should be removed if not required in a later patch. Signed-off-by: Thomas Zimmermann <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/radeon: Replace ttm_bo_reference with ttm_bo_getThomas Zimmermann1-1/+1
The function ttm_bo_get acquires a reference on a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. Signed-off-by: Thomas Zimmermann <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: Replace ttm_bo_unref with ttm_bo_putThomas Zimmermann1-3/+2
The function ttm_bo_put releases a reference to a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. A call to ttm_bo_unref takes the address of the TTM BO object's pointer and clears the pointer's value to NULL. This is not necessary in most cases and sometimes even worked around by the calling code. A call to ttm_bo_put only releases the reference without clearing the pointer. The current behaviour of cleaning the pointer is kept in the calling code, but should be removed if not required in a later patch. v2: * set prefix to drm/amdgpu Signed-off-by: Thomas Zimmermann <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: Replace ttm_bo_reference with ttm_bo_getThomas Zimmermann1-1/+1
The function ttm_bo_get acquires a reference on a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. v2: * changed prefix to drm/amdgpu Signed-off-by: Thomas Zimmermann <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/scheduler: stop setting rq to NULLChristian König1-27/+8
We removed the redundancy of having an extra scheduler field, so we can't set the rq to NULL any more or otherwise won't know which scheduler to use for the cleanup. Just remove the entity from the scheduling list instead. Signed-off-by: Christian König <[email protected]> Acked-by: Nayan Deshmukh <[email protected]> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=107367 Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/scheduler: only kill entity if last user is killed v2Christian König2-1/+7
Note which task is using the entity and only kill it if the last user of the entity is killed. This should prevent problems when entities are leaked to child processes. v2: add missing kernel doc Signed-off-by: Christian König <[email protected]> Reviewed-by: Andrey Grodzovsky <[email protected]> Acked-by: Nayan Deshmukh <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: create an empty bo_list if no handle is providedChristian König1-65/+46
Instead of having extra handling just create an empty bo_list when no handle is provided. Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Reviewed-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: allocate the bo_list array after the listChristian König2-74/+57
This avoids multiple allocations for the head and the array. Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: add bo_list iteratorsChristian König3-39/+43
Add helpers to iterate over all entries in a bo_list. Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Acked-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: nuke amdgpu_bo_list_freeChristian König3-14/+2
The RCU grace period is harmless and avoiding it is not worth the effort of doubling the implementation. Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Reviewed-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: always recreate bo_listChristian König3-15/+12
The bo_list handle is allocated by OP_CREATE, so in OP_UPDATE here we just re-create the bo_list object and replace the handle. This way we don't need locking to protect the bo_list because it's always re-created when changed. Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: move bo_list defines to amdgpu_bo_list.hChristian König2-39/+71
Further demangle amdgpu.h Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Acked-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: add new amdgpu_vm_bo_trace_cs() function v2Christian König4-0/+37
This allows us to trace all VM ranges which should be valid inside a CS. v2: dump mappings without BO as well Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Reviewed-and-tested-by: Andrey Grodzovsky <[email protected]> (v1) Reviewed-by: Huang Rui <[email protected]> (v1) Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: return error if both BOs and bo_list handle is givenChristian König1-3/+6
Return -EINVAL when both the BOs as well as a list handle is provided in the IOCTL. Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Reviewed-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: fix total size calculationChristian König1-1/+1
long might only be 32bit in size and we can easily use more than 4GB here. Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Acked-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/sched: remove unneeded -Iinclude/drm compiler flagMasahiro Yamada1-1/+0
I refactored the include directives under include/drm/ some time ago. This flag is unneeded. Signed-off-by: Masahiro Yamada <[email protected]> Reviewed-by: Christian König <[email protected]> Acked-by: Nayan Deshmukh <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: add proper error handling to amdgpu_bo_list_getChristian König3-23/+20
Otherwise we silently don't use a BO list when the handle is invalid. Signed-off-by: Christian König <[email protected]> Reviewed-by: Chunming Zhou <[email protected]> Reviewed-by: Huang Rui <[email protected]> Reviewed-by: Michel Dänzer <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amdgpu: fix a reversed conditionRex Zhu1-1/+1
This test was reversed so it would end up leading to vddnb value can't be read via hwmon on APU. Reviewed-by: Evan Quan <[email protected]> Reviewed-by: Alex Deucher <[email protected]> Signed-off-by: Rex Zhu <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Cc: [email protected]
2018-07-31drm/amd/pp: Convert voltage unit in mV*4 to mV on CZ/STRex Zhu1-2/+3
the voltage showed in debugfs and hwmon should be in mV Reviewed-by: Evan Quan <[email protected]> Acked-by: Alex Deucher <[email protected]> Signed-off-by: Rex Zhu <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Cc: [email protected]
2018-07-31drm/amd/pp: Delete unused temp variablesRex Zhu1-16/+6
Only delete the dead temp variables in Polaris. Reviewed-by: Alex Deucher <[email protected]> Signed-off-by: Rex Zhu <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-31drm/amd/pp/Polaris12: Fix a chunk of registers missed to programRex Zhu1-0/+43
DIDTConfig_Polaris12[] table missed a big chunk of data. Pointed by aidan.fabius <[email protected]> Reviewed-by: Alex Deucher <[email protected]> Signed-off-by: Rex Zhu <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Cc: [email protected]
2018-07-27drm/amdgpu: clean up the superfluous space and align the comment text for ↵Huang Rui1-56/+51
amdgpu_ttm This patch cleans up spaces and align the text to refine the comment for amdgpu_ttm. Signed-off-by: Huang Rui <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-27drm/amdgpu: correct evict flag for bo moveJunwei Zhang1-2/+2
pass the evict flag instead of hard code Signed-off-by: Junwei Zhang <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-27drm/ttm: Merge hugepage attr changes in ttm_dma_page_put. (v2)Bas Nieuwenhuizen1-7/+4
Every set_pages_array_wb call resulted in cross-core interrupts and TLB flushes. Merge more of them for less overhead. This reduces the time needed to free a 1.6 GiB GTT WC buffer as part of Vulkan CTS from ~2 sec to < 0.25 sec. (Allocation still takes more than 2 sec though) (v2): use set_pages_wb instead of set_memory_wb. Signed-off-by: Bas Nieuwenhuizen <[email protected]> Signed-off-by: Huang Rui <[email protected]> Reviewed-by: Christian König <[email protected]> Reviewed-by: Huang Rui <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-27drm/ttm: clean up non-x86 definitions on ttm_page_allocHuang Rui1-57/+5
All non-x86 definitions are moved to ttm_set_memory header, so remove it from ttm_page_alloc.c. Suggested-by: Christian König <[email protected]> Signed-off-by: Huang Rui <[email protected]> Reviewed-by: Bas Nieuwenhuizen <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-27drm/ttm: clean up non-x86 definitions on ttm_page_alloc_dmaHuang Rui1-44/+4
All non-x86 definitions are moved to ttm_set_memory header, so remove it from ttm_page_alloc_dma.c. Suggested-by: Christian König <[email protected]> Signed-off-by: Huang Rui <[email protected]> Reviewed-by: Bas Nieuwenhuizen <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-27drm/ttm: add ttm_set_memory header (v2)Huang Rui1-0/+128
This patch moves all non-x86 abstraction to the ttm_set_memory header. It is to make function calling more clearly. (v2): add ttm_ prefix. Suggested-by: Christian König <[email protected]> Signed-off-by: Huang Rui <[email protected]> Reviewed-by: Bas Nieuwenhuizen <[email protected]> Reviewed-by: Christian König <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-27drm/amdgpu: implement harvesting support for UVD 7.2 (v3)Alex Deucher5-12/+89
Properly handle cases where one or more instance of the IP block may be harvested. v2: make sure ip_num_rings is initialized amdgpu_queue_mgr.c v3: rebase on Christian's UVD changes, drop unused var Reviewed-by: James Zhu <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-27drm/amd: Add missing fields in atom_integrated_system_info_v1_11Harry Wentland1-4/+11
This structure needs to align with structure in atomfirmware table. Update it. Signed-off-by: Harry Wentland <[email protected]> Acked-by: Alex Deucher <[email protected]> Reviewed-by: Dmytro Laktyushkin <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
2018-07-27drm/amd/display: DC 3.1.59Harry Wentland1-1/+1
Signed-off-by: Harry Wentland <[email protected]> Reviewed-by: Aric Cyr <[email protected]> Acked-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Deucher <[email protected]>