There seems to be a bit of confusing redundancy in a way, how
plane data rate/min cdclk are calculated.
In fact both min cdclk, pixel rate and plane data rate are all
part of the same formula as per BSpec.
However currently we have intel_plane_data_rate, which is used
to calculate plane data rate and which is also used in bandwidth
calculations. However for calculating min_cdclk we have another
piece of code, doing almost same calculation, but a bit differently
and in a different place. However as both are actually part of same
formula, probably would be wise to use plane data rate calculations
as a basis anyway, thus avoiding code duplication and possible bugs
related to this.
Another thing is that I've noticed that during min_cdclk calculations
we account for plane scaling, while for plane data rate, we don't.
crtc->pixel_rate seems to account only for pipe ratio, however it is
clearly stated in BSpec that plane data rate also need to account
plane ratio as well.
So what this commit does is:
- Adds a plane ratio calculation to intel_plane_data_rate
- Removes redundant calculations from skl_plane_min_cdclk which is
used for gen9+ and now uses intel_plane_data_rate as a basis from
there as well.
v2: - Don't use 64 division if not needed(Ville Syrjälä)
- Now use intel_plane_pixel_rate as a basis for calculations both
at intel_plane_data_rate and skl_plane_min_cdclk(Ville Syrjälä)
v3: - Again fix the division macro
- Fix plane_pixel_rate to pixel_rate at intel_plane_pixel_rate
callsites
v4: - Renamed skl_plane_ratio function back(Ville Syrjälä)
v5: - Don't precalculate plane pixel rate for invisible plane,
check for visibility first, as in invisible case it will
have dst_w and dst_h equal to zero, causing divide error.
v6: - Removed useless warn in intel_plane_pixel_rate(Ville Syrjälä)
- Fixed alignment in intel_plane_data_rate(Ville Syrjälä)
- Changed pixel_rate type to be unsigned int in
skl_plane_min_cdclk(Ville Syrjälä)
Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200227150935.2107-1-stanislav.lisovskiy@intel.com
Supposedly both src coordinates have to even when doing 90/270
degree rotation with RGB565. This is definitely true for the
X coordinate (we just get a black screen when it is odd). My
experiments didn't show any misbehaviour with an odd
Y coordinate, but let's trust the spec and reject that one
as well.
v2: Ignore ccs hsub/vsub
v3: Clarify the CCS special (Maarten)
Deal with tgl+ CCS modifiers where we
do need to look at hsub/vsub
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> #v2
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228160523.1064-1-ville.syrjala@linux.intel.com
Some devices with a builtin panel have the panel mounted upside down,
this is indicated by the rotate_180 bit in the BDB_GENERAL_FEATURES VBT
block.
We store this info in dev_priv->vbt.orientation, use this to set the
connector's orientation property so that fbcon and userspace will show
the image the right way up on devices with an upside-down mounted panel.
This fixes the image being upside-down on a Teclast X89 tablet.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228114110.187792-3-hdegoede@redhat.com
Commit 82daca2975 ("drm/i915: Add "panel orientation" property to the
panel connector, v6.") uses hardware state readback to determine if the
GOP is rotating the image by 180 degrees to compensate for upside-down
mounted panels.
When I wrote that commit I tried to find the VBT bits the GOP used to
decide to rotate the image, but I could not find them. Back then I only
looked at the rotation bits in struct mipi_config and these read 0 on
the 1 BYT device I have with an upside-down mounted panel
(a GP-electronic T701 tablet). While working on a similar problem on a
BYT device with an eDP panel I noticed that the new
intel_dsi_get_panel_orientation() helper which gets used on newer
SoCs (Apollo-Lake, etc.) checks the rotate_180 bit in the
BDB_GENERAL_FEATURES VBT block.
I've checked and this bit indeed is set on the GP-electronic T701 tablet,
so using the generic intel_dsi_get_panel_orientation() helper there does
the right thing without needing any extra readback of hw state.
This commit removes the special handling of the panel orientation for
DSI panels on BYT/CHT devices, bringing the handling in line with the
handling of DSI panels on other devices.
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228114110.187792-2-hdegoede@redhat.com
We need to be extremely careful inside i915_request_await_start() as it
needs to walk the list of requests in the foreign timeline with very
little protection. As we hold our own timeline mutex, we can not nest
inside the signaler's timeline mutex, so all that remains is our RCU
protection. However, to be safe we need to tell the compiler that we may
be traversing the list only under RCU protection, and furthermore we
need to start declaring requests as elements of the timeline from their
construction.
Fixes: 9ddc8ec027 ("drm/i915: Eliminate the trylock for awaiting an earlier request")
Fixes: 6a79d84840 ("drm/i915: Lock signaler timeline while navigating")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200227085723.1961649-11-chris@chris-wilson.co.uk
(cherry picked from commit d22d2d073e)
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Commit 60c6a14b48 ("drm/i915/display: Force the state compute phase
once to enable PSR") was forcing the state compute too earlier
causing errors because not everything was initialized, so here
moving to the end of i915_driver_modeset_probe() when the display is
all initialized.
Also fixing the place where it disarm the force probe as during the
atomic check phase errors could happen like the ones due locking and
it would cause PSR to never be enabled if that happens.
Leaving the disarm to the atomic commit phase, intel_psr_enable() or
intel_psr_update() will be called even if the current state do not
allow PSR to be enabled.
v2: Check if intel_dp is null in intel_psr_force_mode_changed_set()
v3: Check intel_dp before get dev_priv
v4:
- renamed intel_psr_force_mode_changed_set() to
intel_psr_set_force_mode_changed()
- removed the set parameter from intel_psr_set_force_mode_changed()
- not calling intel_psr_set_force_mode_changed() from
intel_psr_enable/update(), directly setting it after the same checks
that intel_psr_set_force_mode_changed() does
- moved intel_psr_set_force_mode_changed() arm call to
i915_driver_modeset_probe() as it is a better for a PSR call, all the
functions calls happening between the old and the new function call
will cause issue
[backported to v5.6-rc3]
Fixes: 60c6a14b48 ("drm/i915/display: Force the state compute phase once to enable PSR")
Closes: https://gitlab.freedesktop.org/drm/intel/issues/1151
Tested-by: Ross Zwisler <zwisler@google.com>
Reported-by: Ross Zwisler <zwisler@google.com>
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Anshuman Gupta <anshuman.gupta@intel.com>
Reviewed-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200221212635.11614-1-jose.souza@intel.com
Link: https://patchwork.freedesktop.org/patch/msgid/20200227205540.126135-1-jose.souza@intel.com
(cherry picked from commit df1a5bfc16)
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
This patch makes the internal encoder implementation of the simple
KMS helpers available to drivers.
These simple-encoder helpers initialize an encoder with an empty
implementation. This covers the requirements of most of the existing
DRM drivers. A call to drm_simple_encoder_create() allocates and
initializes an encoder instance, a call to drm_simple_encoder_init()
initializes a pre-allocated instance.
v3:
* remove drm_simple_encoder_create(); not required yet
* provide more precise documentation
v2:
* move simple encoder to KMS helpers
* remove name argument; simplifies implementation
* don't allocate with devm_ interfaces; unsafe with DRM
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228081828.18463-2-tzimmermann@suse.de
Move enabling and disabling HDMI_EN optional regulator to probe() function
to keep track on the regulator status. This fixes following warning if
probe() fails (for example when I2C DDC adapter cannot be yet gathered
due to the missing driver). This fixes following warning observed on
Arndale5250 board with multi_v7_defconfig:
[drm] Failed to get ddc i2c adapter by node
------------[ cut here ]------------
WARNING: CPU: 0 PID: 214 at drivers/regulator/core.c:2051 _regulator_put+0x16c/0x184
Modules linked in: ...
CPU: 0 PID: 214 Comm: systemd-udevd Not tainted 5.6.0-rc2-next-20200219-00040-g38af1dfafdbb #7570
Hardware name: Samsung Exynos (Flattened Device Tree)
[<c0312258>] (unwind_backtrace) from [<c030cc10>] (show_stack+0x10/0x14)
[<c030cc10>] (show_stack) from [<c0f0d3a0>] (dump_stack+0xcc/0xe0)
[<c0f0d3a0>] (dump_stack) from [<c0346a58>] (__warn+0xe0/0xf8)
[<c0346a58>] (__warn) from [<c0346b20>] (warn_slowpath_fmt+0xb0/0xb8)
[<c0346b20>] (warn_slowpath_fmt) from [<c0893f58>] (_regulator_put+0x16c/0x184)
[<c0893f58>] (_regulator_put) from [<c0893f8c>] (regulator_put+0x1c/0x2c)
[<c0893f8c>] (regulator_put) from [<c09b2664>] (release_nodes+0x17c/0x200)
[<c09b2664>] (release_nodes) from [<c09aebe8>] (really_probe+0x10c/0x350)
[<c09aebe8>] (really_probe) from [<c09aefa8>] (driver_probe_device+0x60/0x1a0)
[<c09aefa8>] (driver_probe_device) from [<c09af288>] (device_driver_attach+0x58/0x60)
[<c09af288>] (device_driver_attach) from [<c09af310>] (__driver_attach+0x80/0xbc)
[<c09af310>] (__driver_attach) from [<c09ace34>] (bus_for_each_dev+0x68/0xb4)
[<c09ace34>] (bus_for_each_dev) from [<c09ae00c>] (bus_add_driver+0x130/0x1e8)
[<c09ae00c>] (bus_add_driver) from [<c09afd98>] (driver_register+0x78/0x110)
[<c09afd98>] (driver_register) from [<bf139558>] (exynos_drm_init+0xe8/0x11c [exynosdrm])
[<bf139558>] (exynos_drm_init [exynosdrm]) from [<c0302fa8>] (do_one_initcall+0x50/0x220)
[<c0302fa8>] (do_one_initcall) from [<c03dc02c>] (do_init_module+0x60/0x210)
[<c03dc02c>] (do_init_module) from [<c03daf44>] (load_module+0x1c0c/0x2310)
[<c03daf44>] (load_module) from [<c03db85c>] (sys_finit_module+0xac/0xbc)
[<c03db85c>] (sys_finit_module) from [<c0301000>] (ret_fast_syscall+0x0/0x54)
Exception stack(0xecca3fa8 to 0xecca3ff0)
...
---[ end trace 276c91214635905c ]---
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Writing to the built-in strings arrays doesn't work if driver is loaded
as kernel module. This is also considered as a bad pattern. Fix this by
adding a call to clk_get() with legacy clock name. This fixes following
kernel oops if driver is loaded as module:
Unable to handle kernel paging request at virtual address bf047978
pgd = (ptrval)
[bf047978] *pgd=59344811, *pte=5903c6df, *ppte=5903c65f
Internal error: Oops: 80f [#1] SMP ARM
Modules linked in: mc exynosdrm(+) analogix_dp rtc_s3c exynos_ppmu i2c_gpio
CPU: 1 PID: 212 Comm: systemd-udevd Not tainted 5.6.0-rc2-next-20200219 #326
videodev: Linux video capture interface: v2.00
Hardware name: Samsung Exynos (Flattened Device Tree)
PC is at exynos_dsi_probe+0x1f0/0x384 [exynosdrm]
LR is at exynos_dsi_probe+0x1dc/0x384 [exynosdrm]
...
Process systemd-udevd (pid: 212, stack limit = 0x(ptrval))
...
[<bf03cf14>] (exynos_dsi_probe [exynosdrm]) from [<c09b1ca0>] (platform_drv_probe+0x6c/0xa4)
[<c09b1ca0>] (platform_drv_probe) from [<c09afcb8>] (really_probe+0x210/0x350)
[<c09afcb8>] (really_probe) from [<c09aff74>] (driver_probe_device+0x60/0x1a0)
[<c09aff74>] (driver_probe_device) from [<c09b0254>] (device_driver_attach+0x58/0x60)
[<c09b0254>] (device_driver_attach) from [<c09b02dc>] (__driver_attach+0x80/0xbc)
[<c09b02dc>] (__driver_attach) from [<c09ade00>] (bus_for_each_dev+0x68/0xb4)
[<c09ade00>] (bus_for_each_dev) from [<c09aefd8>] (bus_add_driver+0x130/0x1e8)
[<c09aefd8>] (bus_add_driver) from [<c09b0d64>] (driver_register+0x78/0x110)
[<c09b0d64>] (driver_register) from [<bf038558>] (exynos_drm_init+0xe8/0x11c [exynosdrm])
[<bf038558>] (exynos_drm_init [exynosdrm]) from [<c0302fa8>] (do_one_initcall+0x50/0x220)
[<c0302fa8>] (do_one_initcall) from [<c03dd02c>] (do_init_module+0x60/0x210)
[<c03dd02c>] (do_init_module) from [<c03dbf44>] (load_module+0x1c0c/0x2310)
[<c03dbf44>] (load_module) from [<c03dc85c>] (sys_finit_module+0xac/0xbc)
[<c03dc85c>] (sys_finit_module) from [<c0301000>] (ret_fast_syscall+0x0/0x54)
Exception stack(0xd979bfa8 to 0xd979bff0)
...
---[ end trace db16efe05faab470 ]---
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Properly propagate error value from devm_regulator_bulk_get() and don't
confuse user with meaningless warning about failure in getting regulators
in case of deferred probe.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
The panel-dpi compatible is a fallback that
allows the DT to specify the timing.
When matching panel-dpi expect the device tree to include the
timing information for the display-panel.
Background for this change:
There are a lot of panels and new models hits the market very often.
It is a lost cause trying to chase them all and users of new panels
will often find them in situations that the panel they ues are not
supported by the kernel.
On top of this a lot of panels are customized based on customer
specifications.
Including the panel timing in the device tree allows for a simple
way to describe the actual HW and use this description in a generic
way in the kernel.
This allows uses of proprietary panels, or panels which are not
included in the kernel, to specify the timing in the device tree
together with all the other HW descriptions.
And thus, using the device tree it is then easy to add support
for an otherwise unknown panel.
The current support expect panels that do not require any
delays for prepare/enable/disable/unprepare.
Oleksandr Suvorov replied:
I've just tested this patch on Apalis iMX6Q and Colibri iMX7D using
panel settings from the following patch:
https://lore.kernel.org/linux-arm-kernel/20200115123401.2264293-4-oleksandr.suvorov@toradex.com/
It works for me, thanks!
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Reviewed-by: Oleksandr Suvorov <oleksandr.suvorov@toradex.com>
Tested-by: Oleksandr Suvorov <oleksandr.suvorov@toradex.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Oleksandr Suvorov <oleksandr.suvorov@toradex.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200216181513.28109-6-sam@ravnborg.org
We monitor the health of the system via periodic heartbeat pulses. The
pulses also provide the opportunity to perform garbage collection.
However, we interpret an incomplete pulse (a missed heartbeat) as an
indication that the system is no longer responsive, i.e. hung, and
perform an engine or full GPU reset. Given that the preemption
granularity can be very coarse on a system, we let the sysadmin override
our legacy timeouts which were "optimised" for desktop applications.
The heartbeat interval can be adjusted per-engine using,
/sys/class/drm/card?/engine/*/heartbeat_interval_ms
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Steve Carbonari <steven.carbonari@intel.com>
Tested-by: Steve Carbonari <steven.carbonari@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228131716.3243616-7-chris@chris-wilson.co.uk
After initialising a preemption request, we give the current resident a
small amount of time to vacate the GPU. The preemption request is for a
higher priority context and should be immediate to maintain high
quality of service (and avoid priority inversion). However, the
preemption granularity of the GPU can be quite coarse and so we need a
compromise.
The preempt timeout can be adjusted per-engine using,
/sys/class/drm/card?/engine/*/preempt_timeout_ms
and can be disabled by setting it to 0.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Steve Carbonari <steven.carbonari@intel.com>
Tested-by: Steve Carbonari <steven.carbonari@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228131716.3243616-6-chris@chris-wilson.co.uk
We busywait on an inflight request (one that is currently executing on
HW, and so might complete quickly) prior to setting up an interrupt and
sleeping. The trade off is that we keep an expensive CPU core busy in
order to avoid wake up latency: where that trade off should lie is best
left to the sysadmin.
The busywait mechanism can be compiled out with
./scripts/config --set-val DRM_I915_SPIN_REQUEST 0
The maximum busywait duration can be adjusted per-engine using,
/sys/class/drm/card?/engine/*/ms_busywait_duration_ns
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: Steve Carbonari <steven.carbonari@intel.com>
Tested-by: Steve Carbonari <steven.carbonari@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228131716.3243616-4-chris@chris-wilson.co.uk
Execlists uses a scheduling quantum (a timeslice) to alternate execution
between ready-to-run contexts of equal priority. This ensures that all
users (though only if they of equal importance) have the opportunity to
run and prevents livelocks where contexts may have implicit ordering due
to userspace semaphores.
The timeslicing mechanism can be compiled out with
./scripts/config --set-val DRM_I915_TIMESLICE_DURATION 0
The timeslice duration can be adjusted per-engine using,
/sys/class/drm/card?/engine/*/timeslice_duration_ms
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: Steve Carbonari <steven.carbonari@intel.com>
Tested-by: Steve Carbonari <steven.carbonari@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228131716.3243616-3-chris@chris-wilson.co.uk
Use the per-engine sysfs directory to let userspace discover the
mmio_base of each engine. Prior to recent generations, the user
accessible registers on each engine are at a fixed offset relative to
each engine -- but require absolute addressing. As the absolute address
depends on the actual physical engine, this is not always possible to
determine from userspace (for example icl may expose vcs1 or vcs2 as the
second vcs engine). Make this easy for userspace to discover by
providing the mmio_base in sysfs.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Acked-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Steve Carbonari <steven.carbonari@intel.com>
Tested-by: Steve Carbonari <steven.carbonari@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228131716.3243616-2-chris@chris-wilson.co.uk
Preliminary stub to add engines underneath /sys/class/drm/cardN/, so
that we can expose properties on each engine to the sysadmin.
To start with we have basic analogues of the i915_query ioctl so that we
can pretty print engine discovery from the shell, and flesh out the
directory structure. Later we will add writeable sysadmin properties such
as per-engine timeout controls.
An example tree of the engine properties on Braswell:
/sys/class/drm/card0
└── engine
├── bcs0
│ ├── capabilities
│ ├── class
│ ├── instance
│ ├── known_capabilities
│ └── name
├── rcs0
│ ├── capabilities
│ ├── class
│ ├── instance
│ ├── known_capabilities
│ └── name
├── vcs0
│ ├── capabilities
│ ├── class
│ ├── instance
│ ├── known_capabilities
│ └── name
└── vecs0
├── capabilities
├── class
├── instance
├── known_capabilities
└── name
v2: Include stringified capabilities
v3: Include all known capabilities for futureproofing.
v4: Combine the two caps loops into one
v5: Hide underneath Kconfig.unstable for wider discussion
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Tested-by: Steve Carbonari <steven.carbonari@intel.com>
Reviewed-by: Steve Carbonari <steven.carbonari@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228131716.3243616-1-chris@chris-wilson.co.uk
This adds a message lock to the smu_send_smc_msg* implementations to
protect against concurrent access to the mmu registers used to
communicate with the SMU
v2: Implement for smu_v12_0 as well
v3: Add mutex_init for message_lock
Signed-off-by: Matt Coffin <mcoffin13@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
The new interface reads the argument in the call to send the message, so
this is no longer needed, and shouldn't be used for concurrency safety
reasons.
Signed-off-by: Matt Coffin <mcoffin13@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Move the responsibility for reading argument registers into the
smu_send_smc_msg* implementations, so that adding a message-sending lock
to protect the SMU registers will result in the lock still being held
when the argument is read.
v2: transition smu_v12_0, it's asics, and vega20
Signed-off-by: Matt Coffin <mcoffin13@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
dc to pplib interface is changed for navi1x, renoir.
display_config_changed is not called by dc anymore.
smu_write_watermarks_table is not executed for navi1x, renoir
during boot up.
solution: call smu_write_watermarks_table just after dc pass
watermark clock settings to pplib
Signed-off-by: Hersen Wu <hersenxs.wu@amd.com>
Reviewed-by: Evan Quan <evan.quan@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>