drm fixes for 5.17-rc3
fbdev: - readd fbcon acceleration i915: - fix DP monitor via type-c dock - fix for engine busyness and read timeout with GuC - use ALLOW_FAIL for error capture buffer allocs - don't use interruptible lock on error paths - smatch fix to reject zero sized overlays. amdgpu: - mGPU fan boost fix for beige goby - S0ix fixes - Cyan skillfish hang fix - DCN fixes for DCN 3.1 - DCN fixes for DCN 3.01 - Apple retina panel fix - ttm logic inversion fix dma-buf: - heaps: fix potential spectre v1 gadget kmb: - fix potential oob access mxsfb: - fix NULL ptr deref nouveau: - fix potential oob access during BIOS decode -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmH8whQACgkQDHTzWXnE hr5MRA//Xk5lwTlJJ1QDYVTUwNvyPoFPELjNVROzm4mtspbqYzkPqnguqADm6VaX 1ZHNXJxtCKDz8DZlVbXO4CtvuSfzhSmY7+4tWu6UOjdv7Ab1REIQvAxVS+85HI7X XO7Wxl2U7tanMonsJ8h0ENTjNATWmnI87oPpKMnwUgnQdAW58Ty4GUJLhXIRZRDc 3ycGCqRn/eXkXMsKX75ixV92iht7r5kVB7TWEf52RjqfegH8YGUAVYKzibVt907s +oUJ9La36f9YI4g5tXIFVreyhtV7a5hXT77+WqZjFK6tw9pJYnI4zoTMk6hCM9xE ZPvEJR0KYzAsSqIDE9j5tnysPw+xxBIKzXU9R890z1weKZkBEqZWFlClkngES30g zD1NmjaWaApEVzAvZbAoVwJOwLGs+vUw5ORPWwFG5bvwJJrsER5CSVCEkq2iPIsr m84OBwzyiRq3BzYZc7NzZB4ivoEuI7lx5NKAFskAeEWXenoPmYyUuX8K8HRxpeKY gQJcFUHe5HUaX1CAjV/YxUgjx38byOMvDdprU/FQVgNGqpgV1Et12dQwIgWZ1OYX DzpuU+qQr7Nu/3YdCJIhuOsURoaOWcm3qQwVWGlr/rAJbCM1yPbUK7UlcfkIdJYc 1DeEn03WJj0GGNRinBdOmgOWrwUoLsllMLL+X/3da31eOuEIGnw= =ZH1E -----END PGP SIGNATURE----- Merge tag 'drm-fixes-2022-02-04' of git://anongit.freedesktop.org/drm/drm Pull drm fixes from Dave Airlie: "Regular fixes for the week. Daniel has agreed to bring back the fbcon hw acceleration under a CONFIG option for the non-drm fbdev users, we don't advise turning this on unless you are in the niche that is old fbdev drivers, Since it's essentially a revert and shouldn't be high impact seemed like a good time to do it now. Otherwise, i915 and amdgpu fixes are most of it, along with some minor fixes elsewhere. fbdev: - readd fbcon acceleration i915: - fix DP monitor via type-c dock - fix for engine busyness and read timeout with GuC - use ALLOW_FAIL for error capture buffer allocs - don't use interruptible lock on error paths - smatch fix to reject zero sized overlays. amdgpu: - mGPU fan boost fix for beige goby - S0ix fixes - Cyan skillfish hang fix - DCN fixes for DCN 3.1 - DCN fixes for DCN 3.01 - Apple retina panel fix - ttm logic inversion fix dma-buf: - heaps: fix potential spectre v1 gadget kmb: - fix potential oob access mxsfb: - fix NULL ptr deref nouveau: - fix potential oob access during BIOS decode" * tag 'drm-fixes-2022-02-04' of git://anongit.freedesktop.org/drm/drm: (24 commits) drm: mxsfb: Fix NULL pointer dereference drm/amdgpu: fix logic inversion in check drm/amd: avoid suspend on dGPUs w/ s2idle support when runtime PM enabled drm/amd/display: Force link_rate as LINK_RATE_RBR2 for 2018 15" Apple Retina panels drm/amd/display: revert "Reset fifo after enable otg" drm/amd/display: watermark latencies is not enough on DCN31 drm/amd/display: Update watermark values for DCN301 drm/amdgpu: fix a potential GPU hang on cyan skillfish drm/amd: Only run s3 or s0ix if system is configured properly drm/amd: add support to check whether the system is set to s3 fbcon: Add option to enable legacy hardware acceleration Revert "fbcon: Disable accelerated scrolling" Revert "fbdev: Garbage collect fbdev scrolling acceleration, part 1 (from TODO list)" drm/i915/pmu: Fix KMD and GuC race on accessing busyness dma-buf: heaps: Fix potential spectre v1 gadget drm/amd: Warn users about potential s0ix problems drm/amd/pm: correct the MGpuFanBoost support for Beige Goby drm/nouveau: fix off by one in BIOS boundary checking drm/i915/adlp: Fix TypeC PHY-ready status readout drm/i915/pmu: Use PM timestamp instead of RING TIMESTAMP for reference ...
This commit is contained in:
commit
31462d9e47
|
@ -300,30 +300,6 @@ Contact: Daniel Vetter, Noralf Tronnes
|
|||
|
||||
Level: Advanced
|
||||
|
||||
Garbage collect fbdev scrolling acceleration
|
||||
--------------------------------------------
|
||||
|
||||
Scroll acceleration has been disabled in fbcon. Now it works as the old
|
||||
SCROLL_REDRAW mode. A ton of code was removed in fbcon.c and the hook bmove was
|
||||
removed from fbcon_ops.
|
||||
Remaining tasks:
|
||||
|
||||
- a bunch of the hooks in fbcon_ops could be removed or simplified by calling
|
||||
directly instead of the function table (with a switch on p->rotate)
|
||||
|
||||
- fb_copyarea is unused after this, and can be deleted from all drivers
|
||||
|
||||
- after that, fb_copyarea can be deleted from fb_ops in include/linux/fb.h as
|
||||
well as cfb_copyarea
|
||||
|
||||
Note that not all acceleration code can be deleted, since clearing and cursor
|
||||
support is still accelerated, which might be good candidates for further
|
||||
deletion projects.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
idr_init_base()
|
||||
---------------
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/xarray.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/dma-heap.h>
|
||||
|
@ -135,6 +136,7 @@ static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
|
|||
if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds))
|
||||
return -EINVAL;
|
||||
|
||||
nr = array_index_nospec(nr, ARRAY_SIZE(dma_heap_ioctl_cmds));
|
||||
/* Get the kernel ioctl cmd that matches */
|
||||
kcmd = dma_heap_ioctl_cmds[nr];
|
||||
|
||||
|
|
|
@ -1408,12 +1408,10 @@ int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_sta
|
|||
int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev);
|
||||
|
||||
void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps);
|
||||
bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
|
||||
void amdgpu_acpi_detect(void);
|
||||
#else
|
||||
static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; }
|
||||
static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
|
||||
static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
|
||||
static inline void amdgpu_acpi_detect(void) { }
|
||||
static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return false; }
|
||||
static inline int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev,
|
||||
|
@ -1422,6 +1420,14 @@ static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev,
|
|||
enum amdgpu_ss ss_state) { return 0; }
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
|
||||
bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev);
|
||||
bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
|
||||
#else
|
||||
static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
|
||||
static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; }
|
||||
#endif
|
||||
|
||||
int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
|
||||
uint64_t addr, struct amdgpu_bo **bo,
|
||||
struct amdgpu_bo_va_mapping **mapping);
|
||||
|
|
|
@ -1031,6 +1031,20 @@ void amdgpu_acpi_detect(void)
|
|||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUSPEND)
|
||||
/**
|
||||
* amdgpu_acpi_is_s3_active
|
||||
*
|
||||
* @adev: amdgpu_device_pointer
|
||||
*
|
||||
* returns true if supported, false if not.
|
||||
*/
|
||||
bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
|
||||
{
|
||||
return !(adev->flags & AMD_IS_APU) ||
|
||||
(pm_suspend_target_state == PM_SUSPEND_MEM);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_acpi_is_s0ix_active
|
||||
*
|
||||
|
@ -1040,11 +1054,24 @@ void amdgpu_acpi_detect(void)
|
|||
*/
|
||||
bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_AMD_PMC) && IS_ENABLED(CONFIG_SUSPEND)
|
||||
if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) {
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return pm_suspend_target_state == PM_SUSPEND_TO_IDLE;
|
||||
if (!(adev->flags & AMD_IS_APU) ||
|
||||
(pm_suspend_target_state != PM_SUSPEND_TO_IDLE))
|
||||
return false;
|
||||
|
||||
if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
|
||||
dev_warn_once(adev->dev,
|
||||
"Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n"
|
||||
"To use suspend-to-idle change the sleep mode in BIOS setup.\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !IS_ENABLED(CONFIG_AMD_PMC)
|
||||
dev_warn_once(adev->dev,
|
||||
"Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n");
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif /* CONFIG_AMD_PMC */
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SUSPEND */
|
||||
|
|
|
@ -2246,13 +2246,20 @@ static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work)
|
|||
static int amdgpu_pmops_prepare(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(drm_dev);
|
||||
|
||||
/* Return a positive number here so
|
||||
* DPM_FLAG_SMART_SUSPEND works properly
|
||||
*/
|
||||
if (amdgpu_device_supports_boco(drm_dev))
|
||||
return pm_runtime_suspended(dev) &&
|
||||
pm_suspend_via_firmware();
|
||||
return pm_runtime_suspended(dev);
|
||||
|
||||
/* if we will not support s3 or s2i for the device
|
||||
* then skip suspend
|
||||
*/
|
||||
if (!amdgpu_acpi_is_s0ix_active(adev) &&
|
||||
!amdgpu_acpi_is_s3_active(adev))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1904,7 +1904,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
|
|||
unsigned i;
|
||||
int r;
|
||||
|
||||
if (direct_submit && !ring->sched.ready) {
|
||||
if (!direct_submit && !ring->sched.ready) {
|
||||
DRM_ERROR("Trying to move memory with ring turned off.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -1140,6 +1140,9 @@ static void gmc_v10_0_get_clockgating_state(void *handle, u32 *flags)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 3))
|
||||
return;
|
||||
|
||||
adev->mmhub.funcs->get_clockgating(adev, flags);
|
||||
|
||||
if (adev->ip_versions[ATHUB_HWIP][0] >= IP_VERSION(2, 1, 0))
|
||||
|
|
|
@ -570,32 +570,32 @@ static struct wm_table lpddr5_wm_table = {
|
|||
.wm_inst = WM_A,
|
||||
.wm_type = WM_TYPE_PSTATE_CHG,
|
||||
.pstate_latency_us = 11.65333,
|
||||
.sr_exit_time_us = 7.95,
|
||||
.sr_enter_plus_exit_time_us = 9,
|
||||
.sr_exit_time_us = 13.5,
|
||||
.sr_enter_plus_exit_time_us = 16.5,
|
||||
.valid = true,
|
||||
},
|
||||
{
|
||||
.wm_inst = WM_B,
|
||||
.wm_type = WM_TYPE_PSTATE_CHG,
|
||||
.pstate_latency_us = 11.65333,
|
||||
.sr_exit_time_us = 9.82,
|
||||
.sr_enter_plus_exit_time_us = 11.196,
|
||||
.sr_exit_time_us = 13.5,
|
||||
.sr_enter_plus_exit_time_us = 16.5,
|
||||
.valid = true,
|
||||
},
|
||||
{
|
||||
.wm_inst = WM_C,
|
||||
.wm_type = WM_TYPE_PSTATE_CHG,
|
||||
.pstate_latency_us = 11.65333,
|
||||
.sr_exit_time_us = 9.89,
|
||||
.sr_enter_plus_exit_time_us = 11.24,
|
||||
.sr_exit_time_us = 13.5,
|
||||
.sr_enter_plus_exit_time_us = 16.5,
|
||||
.valid = true,
|
||||
},
|
||||
{
|
||||
.wm_inst = WM_D,
|
||||
.wm_type = WM_TYPE_PSTATE_CHG,
|
||||
.pstate_latency_us = 11.65333,
|
||||
.sr_exit_time_us = 9.748,
|
||||
.sr_enter_plus_exit_time_us = 11.102,
|
||||
.sr_exit_time_us = 13.5,
|
||||
.sr_enter_plus_exit_time_us = 16.5,
|
||||
.valid = true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -329,38 +329,38 @@ static struct clk_bw_params dcn31_bw_params = {
|
|||
|
||||
};
|
||||
|
||||
static struct wm_table ddr4_wm_table = {
|
||||
static struct wm_table ddr5_wm_table = {
|
||||
.entries = {
|
||||
{
|
||||
.wm_inst = WM_A,
|
||||
.wm_type = WM_TYPE_PSTATE_CHG,
|
||||
.pstate_latency_us = 11.72,
|
||||
.sr_exit_time_us = 6.09,
|
||||
.sr_enter_plus_exit_time_us = 7.14,
|
||||
.sr_exit_time_us = 9,
|
||||
.sr_enter_plus_exit_time_us = 11,
|
||||
.valid = true,
|
||||
},
|
||||
{
|
||||
.wm_inst = WM_B,
|
||||
.wm_type = WM_TYPE_PSTATE_CHG,
|
||||
.pstate_latency_us = 11.72,
|
||||
.sr_exit_time_us = 10.12,
|
||||
.sr_enter_plus_exit_time_us = 11.48,
|
||||
.sr_exit_time_us = 9,
|
||||
.sr_enter_plus_exit_time_us = 11,
|
||||
.valid = true,
|
||||
},
|
||||
{
|
||||
.wm_inst = WM_C,
|
||||
.wm_type = WM_TYPE_PSTATE_CHG,
|
||||
.pstate_latency_us = 11.72,
|
||||
.sr_exit_time_us = 10.12,
|
||||
.sr_enter_plus_exit_time_us = 11.48,
|
||||
.sr_exit_time_us = 9,
|
||||
.sr_enter_plus_exit_time_us = 11,
|
||||
.valid = true,
|
||||
},
|
||||
{
|
||||
.wm_inst = WM_D,
|
||||
.wm_type = WM_TYPE_PSTATE_CHG,
|
||||
.pstate_latency_us = 11.72,
|
||||
.sr_exit_time_us = 10.12,
|
||||
.sr_enter_plus_exit_time_us = 11.48,
|
||||
.sr_exit_time_us = 9,
|
||||
.sr_enter_plus_exit_time_us = 11,
|
||||
.valid = true,
|
||||
},
|
||||
}
|
||||
|
@ -687,7 +687,7 @@ void dcn31_clk_mgr_construct(
|
|||
if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
|
||||
dcn31_bw_params.wm_table = lpddr5_wm_table;
|
||||
} else {
|
||||
dcn31_bw_params.wm_table = ddr4_wm_table;
|
||||
dcn31_bw_params.wm_table = ddr5_wm_table;
|
||||
}
|
||||
/* Saved clocks configured at boot for debug purposes */
|
||||
dcn31_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);
|
||||
|
|
|
@ -5597,6 +5597,26 @@ static bool retrieve_link_cap(struct dc_link *link)
|
|||
dp_hw_fw_revision.ieee_fw_rev,
|
||||
sizeof(dp_hw_fw_revision.ieee_fw_rev));
|
||||
|
||||
/* Quirk for Apple MBP 2018 15" Retina panels: wrong DP_MAX_LINK_RATE */
|
||||
{
|
||||
uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 };
|
||||
uint8_t fwrev_mbp_2018[] = { 7, 4 };
|
||||
uint8_t fwrev_mbp_2018_vega[] = { 8, 4 };
|
||||
|
||||
/* We also check for the firmware revision as 16,1 models have an
|
||||
* identical device id and are incorrectly quirked otherwise.
|
||||
*/
|
||||
if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
|
||||
!memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,
|
||||
sizeof(str_mbp_2018)) &&
|
||||
(!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,
|
||||
sizeof(fwrev_mbp_2018)) ||
|
||||
!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,
|
||||
sizeof(fwrev_mbp_2018_vega)))) {
|
||||
link->reported_link_cap.link_rate = LINK_RATE_RBR2;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&link->dpcd_caps.dsc_caps, '\0',
|
||||
sizeof(link->dpcd_caps.dsc_caps));
|
||||
memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
|
||||
|
|
|
@ -1608,11 +1608,6 @@ static enum dc_status apply_single_controller_ctx_to_hw(
|
|||
pipe_ctx->stream_res.stream_enc,
|
||||
pipe_ctx->stream_res.tg->inst);
|
||||
|
||||
if (dc_is_embedded_signal(pipe_ctx->stream->signal) &&
|
||||
pipe_ctx->stream_res.stream_enc->funcs->reset_fifo)
|
||||
pipe_ctx->stream_res.stream_enc->funcs->reset_fifo(
|
||||
pipe_ctx->stream_res.stream_enc);
|
||||
|
||||
if (dc_is_dp_signal(pipe_ctx->stream->signal))
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
|
||||
|
||||
|
|
|
@ -902,19 +902,6 @@ void enc1_stream_encoder_stop_dp_info_packets(
|
|||
|
||||
}
|
||||
|
||||
void enc1_stream_encoder_reset_fifo(
|
||||
struct stream_encoder *enc)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
/* set DIG_START to 0x1 to reset FIFO */
|
||||
REG_UPDATE(DIG_FE_CNTL, DIG_START, 1);
|
||||
udelay(100);
|
||||
|
||||
/* write 0 to take the FIFO out of reset */
|
||||
REG_UPDATE(DIG_FE_CNTL, DIG_START, 0);
|
||||
}
|
||||
|
||||
void enc1_stream_encoder_dp_blank(
|
||||
struct dc_link *link,
|
||||
struct stream_encoder *enc)
|
||||
|
@ -1600,8 +1587,6 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
|
|||
enc1_stream_encoder_send_immediate_sdp_message,
|
||||
.stop_dp_info_packets =
|
||||
enc1_stream_encoder_stop_dp_info_packets,
|
||||
.reset_fifo =
|
||||
enc1_stream_encoder_reset_fifo,
|
||||
.dp_blank =
|
||||
enc1_stream_encoder_dp_blank,
|
||||
.dp_unblank =
|
||||
|
|
|
@ -626,9 +626,6 @@ void enc1_stream_encoder_send_immediate_sdp_message(
|
|||
void enc1_stream_encoder_stop_dp_info_packets(
|
||||
struct stream_encoder *enc);
|
||||
|
||||
void enc1_stream_encoder_reset_fifo(
|
||||
struct stream_encoder *enc);
|
||||
|
||||
void enc1_stream_encoder_dp_blank(
|
||||
struct dc_link *link,
|
||||
struct stream_encoder *enc);
|
||||
|
|
|
@ -593,8 +593,6 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
|
|||
enc1_stream_encoder_send_immediate_sdp_message,
|
||||
.stop_dp_info_packets =
|
||||
enc1_stream_encoder_stop_dp_info_packets,
|
||||
.reset_fifo =
|
||||
enc1_stream_encoder_reset_fifo,
|
||||
.dp_blank =
|
||||
enc1_stream_encoder_dp_blank,
|
||||
.dp_unblank =
|
||||
|
|
|
@ -789,8 +789,6 @@ static const struct stream_encoder_funcs dcn30_str_enc_funcs = {
|
|||
enc3_stream_encoder_update_dp_info_packets,
|
||||
.stop_dp_info_packets =
|
||||
enc1_stream_encoder_stop_dp_info_packets,
|
||||
.reset_fifo =
|
||||
enc1_stream_encoder_reset_fifo,
|
||||
.dp_blank =
|
||||
enc1_stream_encoder_dp_blank,
|
||||
.dp_unblank =
|
||||
|
|
|
@ -164,10 +164,6 @@ struct stream_encoder_funcs {
|
|||
void (*stop_dp_info_packets)(
|
||||
struct stream_encoder *enc);
|
||||
|
||||
void (*reset_fifo)(
|
||||
struct stream_encoder *enc
|
||||
);
|
||||
|
||||
void (*dp_blank)(
|
||||
struct dc_link *link,
|
||||
struct stream_encoder *enc);
|
||||
|
|
|
@ -3696,14 +3696,14 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
|
|||
|
||||
static int sienna_cichlid_enable_mgpu_fan_boost(struct smu_context *smu)
|
||||
{
|
||||
struct smu_table_context *table_context = &smu->smu_table;
|
||||
PPTable_t *smc_pptable = table_context->driver_pptable;
|
||||
uint16_t *mgpu_fan_boost_limit_rpm;
|
||||
|
||||
GET_PPTABLE_MEMBER(MGpuFanBoostLimitRpm, &mgpu_fan_boost_limit_rpm);
|
||||
/*
|
||||
* Skip the MGpuFanBoost setting for those ASICs
|
||||
* which do not support it
|
||||
*/
|
||||
if (!smc_pptable->MGpuFanBoostLimitRpm)
|
||||
if (*mgpu_fan_boost_limit_rpm == 0)
|
||||
return 0;
|
||||
|
||||
return smu_cmn_send_smc_msg_with_param(smu,
|
||||
|
|
|
@ -959,6 +959,9 @@ static int check_overlay_dst(struct intel_overlay *overlay,
|
|||
const struct intel_crtc_state *pipe_config =
|
||||
overlay->crtc->config;
|
||||
|
||||
if (rec->dst_height == 0 || rec->dst_width == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (rec->dst_x < pipe_config->pipe_src_w &&
|
||||
rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w &&
|
||||
rec->dst_y < pipe_config->pipe_src_h &&
|
||||
|
|
|
@ -345,10 +345,11 @@ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port)
|
|||
static bool adl_tc_phy_status_complete(struct intel_digital_port *dig_port)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port);
|
||||
struct intel_uncore *uncore = &i915->uncore;
|
||||
u32 val;
|
||||
|
||||
val = intel_uncore_read(uncore, TCSS_DDI_STATUS(dig_port->tc_phy_fia_idx));
|
||||
val = intel_uncore_read(uncore, TCSS_DDI_STATUS(tc_port));
|
||||
if (val == 0xffffffff) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Port %s: PHY in TCCOLD, assuming not complete\n",
|
||||
|
|
|
@ -2505,9 +2505,14 @@ static int eb_pin_timeline(struct i915_execbuffer *eb, struct intel_context *ce,
|
|||
timeout) < 0) {
|
||||
i915_request_put(rq);
|
||||
|
||||
tl = intel_context_timeline_lock(ce);
|
||||
/*
|
||||
* Error path, cannot use intel_context_timeline_lock as
|
||||
* that is user interruptable and this clean up step
|
||||
* must be done.
|
||||
*/
|
||||
mutex_lock(&ce->timeline->mutex);
|
||||
intel_context_exit(ce);
|
||||
intel_context_timeline_unlock(tl);
|
||||
mutex_unlock(&ce->timeline->mutex);
|
||||
|
||||
if (nonblock)
|
||||
return -EWOULDBLOCK;
|
||||
|
|
|
@ -206,6 +206,11 @@ struct intel_guc {
|
|||
* context usage for overflows.
|
||||
*/
|
||||
struct delayed_work work;
|
||||
|
||||
/**
|
||||
* @shift: Right shift value for the gpm timestamp
|
||||
*/
|
||||
u32 shift;
|
||||
} timestamp;
|
||||
|
||||
#ifdef CONFIG_DRM_I915_SELFTEST
|
||||
|
|
|
@ -1113,6 +1113,19 @@ __extend_last_switch(struct intel_guc *guc, u64 *prev_start, u32 new_start)
|
|||
if (new_start == lower_32_bits(*prev_start))
|
||||
return;
|
||||
|
||||
/*
|
||||
* When gt is unparked, we update the gt timestamp and start the ping
|
||||
* worker that updates the gt_stamp every POLL_TIME_CLKS. As long as gt
|
||||
* is unparked, all switched in contexts will have a start time that is
|
||||
* within +/- POLL_TIME_CLKS of the most recent gt_stamp.
|
||||
*
|
||||
* If neither gt_stamp nor new_start has rolled over, then the
|
||||
* gt_stamp_hi does not need to be adjusted, however if one of them has
|
||||
* rolled over, we need to adjust gt_stamp_hi accordingly.
|
||||
*
|
||||
* The below conditions address the cases of new_start rollover and
|
||||
* gt_stamp_last rollover respectively.
|
||||
*/
|
||||
if (new_start < gt_stamp_last &&
|
||||
(new_start - gt_stamp_last) <= POLL_TIME_CLKS)
|
||||
gt_stamp_hi++;
|
||||
|
@ -1124,17 +1137,45 @@ __extend_last_switch(struct intel_guc *guc, u64 *prev_start, u32 new_start)
|
|||
*prev_start = ((u64)gt_stamp_hi << 32) | new_start;
|
||||
}
|
||||
|
||||
static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
|
||||
/*
|
||||
* GuC updates shared memory and KMD reads it. Since this is not synchronized,
|
||||
* we run into a race where the value read is inconsistent. Sometimes the
|
||||
* inconsistency is in reading the upper MSB bytes of the last_in value when
|
||||
* this race occurs. 2 types of cases are seen - upper 8 bits are zero and upper
|
||||
* 24 bits are zero. Since these are non-zero values, it is non-trivial to
|
||||
* determine validity of these values. Instead we read the values multiple times
|
||||
* until they are consistent. In test runs, 3 attempts results in consistent
|
||||
* values. The upper bound is set to 6 attempts and may need to be tuned as per
|
||||
* any new occurences.
|
||||
*/
|
||||
static void __get_engine_usage_record(struct intel_engine_cs *engine,
|
||||
u32 *last_in, u32 *id, u32 *total)
|
||||
{
|
||||
struct guc_engine_usage_record *rec = intel_guc_engine_usage(engine);
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
*last_in = READ_ONCE(rec->last_switch_in_stamp);
|
||||
*id = READ_ONCE(rec->current_context_index);
|
||||
*total = READ_ONCE(rec->total_runtime);
|
||||
|
||||
if (READ_ONCE(rec->last_switch_in_stamp) == *last_in &&
|
||||
READ_ONCE(rec->current_context_index) == *id &&
|
||||
READ_ONCE(rec->total_runtime) == *total)
|
||||
break;
|
||||
} while (++i < 6);
|
||||
}
|
||||
|
||||
static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct intel_engine_guc_stats *stats = &engine->stats.guc;
|
||||
struct intel_guc *guc = &engine->gt->uc.guc;
|
||||
u32 last_switch = rec->last_switch_in_stamp;
|
||||
u32 ctx_id = rec->current_context_index;
|
||||
u32 total = rec->total_runtime;
|
||||
u32 last_switch, ctx_id, total;
|
||||
|
||||
lockdep_assert_held(&guc->timestamp.lock);
|
||||
|
||||
__get_engine_usage_record(engine, &last_switch, &ctx_id, &total);
|
||||
|
||||
stats->running = ctx_id != ~0U && last_switch;
|
||||
if (stats->running)
|
||||
__extend_last_switch(guc, &stats->start_gt_clk, last_switch);
|
||||
|
@ -1149,23 +1190,51 @@ static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
|
|||
}
|
||||
}
|
||||
|
||||
static void guc_update_pm_timestamp(struct intel_guc *guc,
|
||||
struct intel_engine_cs *engine,
|
||||
ktime_t *now)
|
||||
static u32 gpm_timestamp_shift(struct intel_gt *gt)
|
||||
{
|
||||
u32 gt_stamp_now, gt_stamp_hi;
|
||||
intel_wakeref_t wakeref;
|
||||
u32 reg, shift;
|
||||
|
||||
with_intel_runtime_pm(gt->uncore->rpm, wakeref)
|
||||
reg = intel_uncore_read(gt->uncore, RPM_CONFIG0);
|
||||
|
||||
shift = (reg & GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK) >>
|
||||
GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT;
|
||||
|
||||
return 3 - shift;
|
||||
}
|
||||
|
||||
static u64 gpm_timestamp(struct intel_gt *gt)
|
||||
{
|
||||
u32 lo, hi, old_hi, loop = 0;
|
||||
|
||||
hi = intel_uncore_read(gt->uncore, MISC_STATUS1);
|
||||
do {
|
||||
lo = intel_uncore_read(gt->uncore, MISC_STATUS0);
|
||||
old_hi = hi;
|
||||
hi = intel_uncore_read(gt->uncore, MISC_STATUS1);
|
||||
} while (old_hi != hi && loop++ < 2);
|
||||
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
static void guc_update_pm_timestamp(struct intel_guc *guc, ktime_t *now)
|
||||
{
|
||||
struct intel_gt *gt = guc_to_gt(guc);
|
||||
u32 gt_stamp_lo, gt_stamp_hi;
|
||||
u64 gpm_ts;
|
||||
|
||||
lockdep_assert_held(&guc->timestamp.lock);
|
||||
|
||||
gt_stamp_hi = upper_32_bits(guc->timestamp.gt_stamp);
|
||||
gt_stamp_now = intel_uncore_read(engine->uncore,
|
||||
RING_TIMESTAMP(engine->mmio_base));
|
||||
gpm_ts = gpm_timestamp(gt) >> guc->timestamp.shift;
|
||||
gt_stamp_lo = lower_32_bits(gpm_ts);
|
||||
*now = ktime_get();
|
||||
|
||||
if (gt_stamp_now < lower_32_bits(guc->timestamp.gt_stamp))
|
||||
if (gt_stamp_lo < lower_32_bits(guc->timestamp.gt_stamp))
|
||||
gt_stamp_hi++;
|
||||
|
||||
guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_now;
|
||||
guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_lo;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1208,8 +1277,12 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now)
|
|||
if (!in_reset && intel_gt_pm_get_if_awake(gt)) {
|
||||
stats_saved = *stats;
|
||||
gt_stamp_saved = guc->timestamp.gt_stamp;
|
||||
/*
|
||||
* Update gt_clks, then gt timestamp to simplify the 'gt_stamp -
|
||||
* start_gt_clk' calculation below for active engines.
|
||||
*/
|
||||
guc_update_engine_gt_clks(engine);
|
||||
guc_update_pm_timestamp(guc, engine, now);
|
||||
guc_update_pm_timestamp(guc, now);
|
||||
intel_gt_pm_put_async(gt);
|
||||
if (i915_reset_count(gpu_error) != reset_count) {
|
||||
*stats = stats_saved;
|
||||
|
@ -1241,8 +1314,8 @@ static void __reset_guc_busyness_stats(struct intel_guc *guc)
|
|||
|
||||
spin_lock_irqsave(&guc->timestamp.lock, flags);
|
||||
|
||||
guc_update_pm_timestamp(guc, &unused);
|
||||
for_each_engine(engine, gt, id) {
|
||||
guc_update_pm_timestamp(guc, engine, &unused);
|
||||
guc_update_engine_gt_clks(engine);
|
||||
engine->stats.guc.prev_total = 0;
|
||||
}
|
||||
|
@ -1259,10 +1332,11 @@ static void __update_guc_busyness_stats(struct intel_guc *guc)
|
|||
ktime_t unused;
|
||||
|
||||
spin_lock_irqsave(&guc->timestamp.lock, flags);
|
||||
for_each_engine(engine, gt, id) {
|
||||
guc_update_pm_timestamp(guc, engine, &unused);
|
||||
|
||||
guc_update_pm_timestamp(guc, &unused);
|
||||
for_each_engine(engine, gt, id)
|
||||
guc_update_engine_gt_clks(engine);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&guc->timestamp.lock, flags);
|
||||
}
|
||||
|
||||
|
@ -1335,10 +1409,15 @@ void intel_guc_busyness_park(struct intel_gt *gt)
|
|||
void intel_guc_busyness_unpark(struct intel_gt *gt)
|
||||
{
|
||||
struct intel_guc *guc = >->uc.guc;
|
||||
unsigned long flags;
|
||||
ktime_t unused;
|
||||
|
||||
if (!guc_submission_initialized(guc))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&guc->timestamp.lock, flags);
|
||||
guc_update_pm_timestamp(guc, &unused);
|
||||
spin_unlock_irqrestore(&guc->timestamp.lock, flags);
|
||||
mod_delayed_work(system_highpri_wq, &guc->timestamp.work,
|
||||
guc->timestamp.ping_delay);
|
||||
}
|
||||
|
@ -1783,6 +1862,7 @@ int intel_guc_submission_init(struct intel_guc *guc)
|
|||
spin_lock_init(&guc->timestamp.lock);
|
||||
INIT_DELAYED_WORK(&guc->timestamp.work, guc_timestamp_ping);
|
||||
guc->timestamp.ping_delay = (POLL_TIME_CLKS / gt->clock_frequency + 1) * HZ;
|
||||
guc->timestamp.shift = gpm_timestamp_shift(gt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1522,7 +1522,7 @@ capture_engine(struct intel_engine_cs *engine,
|
|||
struct i915_request *rq = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
ee = intel_engine_coredump_alloc(engine, GFP_KERNEL);
|
||||
ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL);
|
||||
if (!ee)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -2684,7 +2684,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
|||
#define RING_WAIT (1 << 11) /* gen3+, PRBx_CTL */
|
||||
#define RING_WAIT_SEMAPHORE (1 << 10) /* gen6+ */
|
||||
|
||||
#define GUCPMTIMESTAMP _MMIO(0xC3E8)
|
||||
#define MISC_STATUS0 _MMIO(0xA500)
|
||||
#define MISC_STATUS1 _MMIO(0xA504)
|
||||
|
||||
/* There are 16 64-bit CS General Purpose Registers per-engine on Gen8+ */
|
||||
#define GEN8_RING_CS_GPR(base, n) _MMIO((base) + 0x600 + (n) * 8)
|
||||
|
|
|
@ -158,12 +158,6 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane,
|
|||
case LAYER_1:
|
||||
kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL2_ENABLE;
|
||||
break;
|
||||
case LAYER_2:
|
||||
kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL1_ENABLE;
|
||||
break;
|
||||
case LAYER_3:
|
||||
kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL2_ENABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
kmb->plane_status[plane_id].disable = true;
|
||||
|
|
|
@ -361,7 +361,11 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
|
|||
bridge_state =
|
||||
drm_atomic_get_new_bridge_state(state,
|
||||
mxsfb->bridge);
|
||||
bus_format = bridge_state->input_bus_cfg.format;
|
||||
if (!bridge_state)
|
||||
bus_format = MEDIA_BUS_FMT_FIXED;
|
||||
else
|
||||
bus_format = bridge_state->input_bus_cfg.format;
|
||||
|
||||
if (bus_format == MEDIA_BUS_FMT_FIXED) {
|
||||
dev_warn_once(drm->dev,
|
||||
"Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
|
||||
|
|
|
@ -38,7 +38,7 @@ nvbios_addr(struct nvkm_bios *bios, u32 *addr, u8 size)
|
|||
*addr += bios->imaged_addr;
|
||||
}
|
||||
|
||||
if (unlikely(*addr + size >= bios->size)) {
|
||||
if (unlikely(*addr + size > bios->size)) {
|
||||
nvkm_error(&bios->subdev, "OOB %d %08x %08x\n", size, p, *addr);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,26 @@ config FRAMEBUFFER_CONSOLE
|
|||
help
|
||||
Low-level framebuffer-based console driver.
|
||||
|
||||
config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
|
||||
bool "Enable legacy fbcon hardware acceleration code"
|
||||
depends on FRAMEBUFFER_CONSOLE
|
||||
default y if PARISC
|
||||
default n
|
||||
help
|
||||
This option enables the fbcon (framebuffer text-based) hardware
|
||||
acceleration for graphics drivers which were written for the fbdev
|
||||
graphics interface.
|
||||
|
||||
On modern machines, on mainstream machines (like x86-64) or when
|
||||
using a modern Linux distribution those fbdev drivers usually aren't used.
|
||||
So enabling this option wouldn't have any effect, which is why you want
|
||||
to disable this option on such newer machines.
|
||||
|
||||
If you compile this kernel for older machines which still require the
|
||||
fbdev drivers, you may want to say Y.
|
||||
|
||||
If unsure, select n.
|
||||
|
||||
config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
|
||||
bool "Map the console to the primary display device"
|
||||
depends on FRAMEBUFFER_CONSOLE
|
||||
|
|
|
@ -43,6 +43,21 @@ static void update_attr(u8 *dst, u8 *src, int attribute,
|
|||
}
|
||||
}
|
||||
|
||||
static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fb_copyarea area;
|
||||
|
||||
area.sx = sx * vc->vc_font.width;
|
||||
area.sy = sy * vc->vc_font.height;
|
||||
area.dx = dx * vc->vc_font.width;
|
||||
area.dy = dy * vc->vc_font.height;
|
||||
area.height = height * vc->vc_font.height;
|
||||
area.width = width * vc->vc_font.width;
|
||||
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
|
||||
static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
|
@ -378,6 +393,7 @@ static int bit_update_start(struct fb_info *info)
|
|||
|
||||
void fbcon_set_bitops(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->bmove = bit_bmove;
|
||||
ops->clear = bit_clear;
|
||||
ops->putcs = bit_putcs;
|
||||
ops->clear_margins = bit_clear_margins;
|
||||
|
|
|
@ -173,6 +173,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
|
|||
int count, int ypos, int xpos);
|
||||
static void fbcon_clear_margins(struct vc_data *vc, int bottom_only);
|
||||
static void fbcon_cursor(struct vc_data *vc, int mode);
|
||||
static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
|
||||
int height, int width);
|
||||
static int fbcon_switch(struct vc_data *vc);
|
||||
static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
|
||||
static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
|
||||
|
@ -180,8 +182,16 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
|
|||
/*
|
||||
* Internal routines
|
||||
*/
|
||||
static __inline__ void ywrap_up(struct vc_data *vc, int count);
|
||||
static __inline__ void ywrap_down(struct vc_data *vc, int count);
|
||||
static __inline__ void ypan_up(struct vc_data *vc, int count);
|
||||
static __inline__ void ypan_down(struct vc_data *vc, int count);
|
||||
static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
|
||||
int dy, int dx, int height, int width, u_int y_break);
|
||||
static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
|
||||
int unit);
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int dy);
|
||||
static void fbcon_modechanged(struct fb_info *info);
|
||||
static void fbcon_set_all_vcs(struct fb_info *info);
|
||||
static void fbcon_start(void);
|
||||
|
@ -1015,7 +1025,7 @@ static void fbcon_init(struct vc_data *vc, int init)
|
|||
struct vc_data *svc = *default_mode;
|
||||
struct fbcon_display *t, *p = &fb_display[vc->vc_num];
|
||||
int logo = 1, new_rows, new_cols, rows, cols;
|
||||
int ret;
|
||||
int cap, ret;
|
||||
|
||||
if (WARN_ON(info_idx == -1))
|
||||
return;
|
||||
|
@ -1024,6 +1034,7 @@ static void fbcon_init(struct vc_data *vc, int init)
|
|||
con2fb_map[vc->vc_num] = info_idx;
|
||||
|
||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
cap = info->flags;
|
||||
|
||||
if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET)
|
||||
logo_shown = FBCON_LOGO_DONTSHOW;
|
||||
|
@ -1125,6 +1136,14 @@ static void fbcon_init(struct vc_data *vc, int init)
|
|||
|
||||
ops->graphics = 0;
|
||||
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
|
||||
if ((cap & FBINFO_HWACCEL_COPYAREA) &&
|
||||
!(cap & FBINFO_HWACCEL_DISABLED))
|
||||
p->scrollmode = SCROLL_MOVE;
|
||||
else /* default to something safe */
|
||||
p->scrollmode = SCROLL_REDRAW;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ++guenther: console.c:vc_allocate() relies on initializing
|
||||
* vc_{cols,rows}, but we must not set those if we are only
|
||||
|
@ -1211,13 +1230,14 @@ finished:
|
|||
* This system is now divided into two levels because of complications
|
||||
* caused by hardware scrolling. Top level functions:
|
||||
*
|
||||
* fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
|
||||
* fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
|
||||
*
|
||||
* handles y values in range [0, scr_height-1] that correspond to real
|
||||
* screen positions. y_wrap shift means that first line of bitmap may be
|
||||
* anywhere on this display. These functions convert lineoffsets to
|
||||
* bitmap offsets and deal with the wrap-around case by splitting blits.
|
||||
*
|
||||
* fbcon_bmove_physical_8() -- These functions fast implementations
|
||||
* fbcon_clear_physical_8() -- of original fbcon_XXX fns.
|
||||
* fbcon_putc_physical_8() -- (font width != 8) may be added later
|
||||
*
|
||||
|
@ -1390,6 +1410,224 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
|
|||
}
|
||||
}
|
||||
|
||||
static __inline__ void ywrap_up(struct vc_data *vc, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
p->yscroll += count;
|
||||
if (p->yscroll >= p->vrows) /* Deal with wrap */
|
||||
p->yscroll -= p->vrows;
|
||||
ops->var.xoffset = 0;
|
||||
ops->var.yoffset = p->yscroll * vc->vc_font.height;
|
||||
ops->var.vmode |= FB_VMODE_YWRAP;
|
||||
ops->update_start(info);
|
||||
scrollback_max += count;
|
||||
if (scrollback_max > scrollback_phys_max)
|
||||
scrollback_max = scrollback_phys_max;
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
static __inline__ void ywrap_down(struct vc_data *vc, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
p->yscroll -= count;
|
||||
if (p->yscroll < 0) /* Deal with wrap */
|
||||
p->yscroll += p->vrows;
|
||||
ops->var.xoffset = 0;
|
||||
ops->var.yoffset = p->yscroll * vc->vc_font.height;
|
||||
ops->var.vmode |= FB_VMODE_YWRAP;
|
||||
ops->update_start(info);
|
||||
scrollback_max -= count;
|
||||
if (scrollback_max < 0)
|
||||
scrollback_max = 0;
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
static __inline__ void ypan_up(struct vc_data *vc, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
p->yscroll += count;
|
||||
if (p->yscroll > p->vrows - vc->vc_rows) {
|
||||
ops->bmove(vc, info, p->vrows - vc->vc_rows,
|
||||
0, 0, 0, vc->vc_rows, vc->vc_cols);
|
||||
p->yscroll -= p->vrows - vc->vc_rows;
|
||||
}
|
||||
|
||||
ops->var.xoffset = 0;
|
||||
ops->var.yoffset = p->yscroll * vc->vc_font.height;
|
||||
ops->var.vmode &= ~FB_VMODE_YWRAP;
|
||||
ops->update_start(info);
|
||||
fbcon_clear_margins(vc, 1);
|
||||
scrollback_max += count;
|
||||
if (scrollback_max > scrollback_phys_max)
|
||||
scrollback_max = scrollback_phys_max;
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
p->yscroll += count;
|
||||
|
||||
if (p->yscroll > p->vrows - vc->vc_rows) {
|
||||
p->yscroll -= p->vrows - vc->vc_rows;
|
||||
fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
|
||||
}
|
||||
|
||||
ops->var.xoffset = 0;
|
||||
ops->var.yoffset = p->yscroll * vc->vc_font.height;
|
||||
ops->var.vmode &= ~FB_VMODE_YWRAP;
|
||||
ops->update_start(info);
|
||||
fbcon_clear_margins(vc, 1);
|
||||
scrollback_max += count;
|
||||
if (scrollback_max > scrollback_phys_max)
|
||||
scrollback_max = scrollback_phys_max;
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
static __inline__ void ypan_down(struct vc_data *vc, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
p->yscroll -= count;
|
||||
if (p->yscroll < 0) {
|
||||
ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
|
||||
0, vc->vc_rows, vc->vc_cols);
|
||||
p->yscroll += p->vrows - vc->vc_rows;
|
||||
}
|
||||
|
||||
ops->var.xoffset = 0;
|
||||
ops->var.yoffset = p->yscroll * vc->vc_font.height;
|
||||
ops->var.vmode &= ~FB_VMODE_YWRAP;
|
||||
ops->update_start(info);
|
||||
fbcon_clear_margins(vc, 1);
|
||||
scrollback_max -= count;
|
||||
if (scrollback_max < 0)
|
||||
scrollback_max = 0;
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
p->yscroll -= count;
|
||||
|
||||
if (p->yscroll < 0) {
|
||||
p->yscroll += p->vrows - vc->vc_rows;
|
||||
fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
|
||||
}
|
||||
|
||||
ops->var.xoffset = 0;
|
||||
ops->var.yoffset = p->yscroll * vc->vc_font.height;
|
||||
ops->var.vmode &= ~FB_VMODE_YWRAP;
|
||||
ops->update_start(info);
|
||||
fbcon_clear_margins(vc, 1);
|
||||
scrollback_max -= count;
|
||||
if (scrollback_max < 0)
|
||||
scrollback_max = 0;
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int dy)
|
||||
{
|
||||
unsigned short *s = (unsigned short *)
|
||||
(vc->vc_origin + vc->vc_size_row * line);
|
||||
|
||||
while (count--) {
|
||||
unsigned short *start = s;
|
||||
unsigned short *le = advance_row(s, 1);
|
||||
unsigned short c;
|
||||
int x = 0;
|
||||
unsigned short attr = 1;
|
||||
|
||||
do {
|
||||
c = scr_readw(s);
|
||||
if (attr != (c & 0xff00)) {
|
||||
attr = c & 0xff00;
|
||||
if (s > start) {
|
||||
fbcon_putcs(vc, start, s - start,
|
||||
dy, x);
|
||||
x += s - start;
|
||||
start = s;
|
||||
}
|
||||
}
|
||||
console_conditional_schedule();
|
||||
s++;
|
||||
} while (s < le);
|
||||
if (s > start)
|
||||
fbcon_putcs(vc, start, s - start, dy, x);
|
||||
console_conditional_schedule();
|
||||
dy++;
|
||||
}
|
||||
}
|
||||
|
||||
static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
|
||||
struct fbcon_display *p, int line, int count, int ycount)
|
||||
{
|
||||
int offset = ycount * vc->vc_cols;
|
||||
unsigned short *d = (unsigned short *)
|
||||
(vc->vc_origin + vc->vc_size_row * line);
|
||||
unsigned short *s = d + offset;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
while (count--) {
|
||||
unsigned short *start = s;
|
||||
unsigned short *le = advance_row(s, 1);
|
||||
unsigned short c;
|
||||
int x = 0;
|
||||
|
||||
do {
|
||||
c = scr_readw(s);
|
||||
|
||||
if (c == scr_readw(d)) {
|
||||
if (s > start) {
|
||||
ops->bmove(vc, info, line + ycount, x,
|
||||
line, x, 1, s-start);
|
||||
x += s - start + 1;
|
||||
start = s + 1;
|
||||
} else {
|
||||
x++;
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
scr_writew(c, d);
|
||||
console_conditional_schedule();
|
||||
s++;
|
||||
d++;
|
||||
} while (s < le);
|
||||
if (s > start)
|
||||
ops->bmove(vc, info, line + ycount, x, line, x, 1,
|
||||
s-start);
|
||||
console_conditional_schedule();
|
||||
if (ycount > 0)
|
||||
line++;
|
||||
else {
|
||||
line--;
|
||||
/* NOTE: We subtract two lines from these pointers */
|
||||
s -= vc->vc_size_row;
|
||||
d -= vc->vc_size_row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int offset)
|
||||
{
|
||||
|
@ -1450,6 +1688,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
|
||||
|
||||
if (fbcon_is_inactive(vc, info))
|
||||
return true;
|
||||
|
@ -1466,32 +1705,291 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|||
case SM_UP:
|
||||
if (count > vc->vc_rows) /* Maximum realistic size */
|
||||
count = vc->vc_rows;
|
||||
fbcon_redraw(vc, p, t, b - t - count,
|
||||
count * vc->vc_cols);
|
||||
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
||||
scr_memsetw((unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row *
|
||||
(b - count)),
|
||||
vc->vc_video_erase_char,
|
||||
vc->vc_size_row * count);
|
||||
return true;
|
||||
if (logo_shown >= 0)
|
||||
goto redraw_up;
|
||||
switch (fb_scrollmode(p)) {
|
||||
case SCROLL_MOVE:
|
||||
fbcon_redraw_blit(vc, info, p, t, b - t - count,
|
||||
count);
|
||||
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
||||
scr_memsetw((unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row *
|
||||
(b - count)),
|
||||
vc->vc_video_erase_char,
|
||||
vc->vc_size_row * count);
|
||||
return true;
|
||||
|
||||
case SCROLL_WRAP_MOVE:
|
||||
if (b - t - count > 3 * vc->vc_rows >> 2) {
|
||||
if (t > 0)
|
||||
fbcon_bmove(vc, 0, 0, count, 0, t,
|
||||
vc->vc_cols);
|
||||
ywrap_up(vc, count);
|
||||
if (vc->vc_rows - b > 0)
|
||||
fbcon_bmove(vc, b - count, 0, b, 0,
|
||||
vc->vc_rows - b,
|
||||
vc->vc_cols);
|
||||
} else if (info->flags & FBINFO_READS_FAST)
|
||||
fbcon_bmove(vc, t + count, 0, t, 0,
|
||||
b - t - count, vc->vc_cols);
|
||||
else
|
||||
goto redraw_up;
|
||||
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
||||
break;
|
||||
|
||||
case SCROLL_PAN_REDRAW:
|
||||
if ((p->yscroll + count <=
|
||||
2 * (p->vrows - vc->vc_rows))
|
||||
&& ((!scroll_partial && (b - t == vc->vc_rows))
|
||||
|| (scroll_partial
|
||||
&& (b - t - count >
|
||||
3 * vc->vc_rows >> 2)))) {
|
||||
if (t > 0)
|
||||
fbcon_redraw_move(vc, p, 0, t, count);
|
||||
ypan_up_redraw(vc, t, count);
|
||||
if (vc->vc_rows - b > 0)
|
||||
fbcon_redraw_move(vc, p, b,
|
||||
vc->vc_rows - b, b);
|
||||
} else
|
||||
fbcon_redraw_move(vc, p, t + count, b - t - count, t);
|
||||
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
||||
break;
|
||||
|
||||
case SCROLL_PAN_MOVE:
|
||||
if ((p->yscroll + count <=
|
||||
2 * (p->vrows - vc->vc_rows))
|
||||
&& ((!scroll_partial && (b - t == vc->vc_rows))
|
||||
|| (scroll_partial
|
||||
&& (b - t - count >
|
||||
3 * vc->vc_rows >> 2)))) {
|
||||
if (t > 0)
|
||||
fbcon_bmove(vc, 0, 0, count, 0, t,
|
||||
vc->vc_cols);
|
||||
ypan_up(vc, count);
|
||||
if (vc->vc_rows - b > 0)
|
||||
fbcon_bmove(vc, b - count, 0, b, 0,
|
||||
vc->vc_rows - b,
|
||||
vc->vc_cols);
|
||||
} else if (info->flags & FBINFO_READS_FAST)
|
||||
fbcon_bmove(vc, t + count, 0, t, 0,
|
||||
b - t - count, vc->vc_cols);
|
||||
else
|
||||
goto redraw_up;
|
||||
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
||||
break;
|
||||
|
||||
case SCROLL_REDRAW:
|
||||
redraw_up:
|
||||
fbcon_redraw(vc, p, t, b - t - count,
|
||||
count * vc->vc_cols);
|
||||
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
||||
scr_memsetw((unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row *
|
||||
(b - count)),
|
||||
vc->vc_video_erase_char,
|
||||
vc->vc_size_row * count);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SM_DOWN:
|
||||
if (count > vc->vc_rows) /* Maximum realistic size */
|
||||
count = vc->vc_rows;
|
||||
fbcon_redraw(vc, p, b - 1, b - t - count,
|
||||
-count * vc->vc_cols);
|
||||
fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
||||
scr_memsetw((unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row *
|
||||
t),
|
||||
vc->vc_video_erase_char,
|
||||
vc->vc_size_row * count);
|
||||
return true;
|
||||
if (logo_shown >= 0)
|
||||
goto redraw_down;
|
||||
switch (fb_scrollmode(p)) {
|
||||
case SCROLL_MOVE:
|
||||
fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
|
||||
-count);
|
||||
fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
||||
scr_memsetw((unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row *
|
||||
t),
|
||||
vc->vc_video_erase_char,
|
||||
vc->vc_size_row * count);
|
||||
return true;
|
||||
|
||||
case SCROLL_WRAP_MOVE:
|
||||
if (b - t - count > 3 * vc->vc_rows >> 2) {
|
||||
if (vc->vc_rows - b > 0)
|
||||
fbcon_bmove(vc, b, 0, b - count, 0,
|
||||
vc->vc_rows - b,
|
||||
vc->vc_cols);
|
||||
ywrap_down(vc, count);
|
||||
if (t > 0)
|
||||
fbcon_bmove(vc, count, 0, 0, 0, t,
|
||||
vc->vc_cols);
|
||||
} else if (info->flags & FBINFO_READS_FAST)
|
||||
fbcon_bmove(vc, t, 0, t + count, 0,
|
||||
b - t - count, vc->vc_cols);
|
||||
else
|
||||
goto redraw_down;
|
||||
fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
||||
break;
|
||||
|
||||
case SCROLL_PAN_MOVE:
|
||||
if ((count - p->yscroll <= p->vrows - vc->vc_rows)
|
||||
&& ((!scroll_partial && (b - t == vc->vc_rows))
|
||||
|| (scroll_partial
|
||||
&& (b - t - count >
|
||||
3 * vc->vc_rows >> 2)))) {
|
||||
if (vc->vc_rows - b > 0)
|
||||
fbcon_bmove(vc, b, 0, b - count, 0,
|
||||
vc->vc_rows - b,
|
||||
vc->vc_cols);
|
||||
ypan_down(vc, count);
|
||||
if (t > 0)
|
||||
fbcon_bmove(vc, count, 0, 0, 0, t,
|
||||
vc->vc_cols);
|
||||
} else if (info->flags & FBINFO_READS_FAST)
|
||||
fbcon_bmove(vc, t, 0, t + count, 0,
|
||||
b - t - count, vc->vc_cols);
|
||||
else
|
||||
goto redraw_down;
|
||||
fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
||||
break;
|
||||
|
||||
case SCROLL_PAN_REDRAW:
|
||||
if ((count - p->yscroll <= p->vrows - vc->vc_rows)
|
||||
&& ((!scroll_partial && (b - t == vc->vc_rows))
|
||||
|| (scroll_partial
|
||||
&& (b - t - count >
|
||||
3 * vc->vc_rows >> 2)))) {
|
||||
if (vc->vc_rows - b > 0)
|
||||
fbcon_redraw_move(vc, p, b, vc->vc_rows - b,
|
||||
b - count);
|
||||
ypan_down_redraw(vc, t, count);
|
||||
if (t > 0)
|
||||
fbcon_redraw_move(vc, p, count, t, 0);
|
||||
} else
|
||||
fbcon_redraw_move(vc, p, t, b - t - count, t + count);
|
||||
fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
||||
break;
|
||||
|
||||
case SCROLL_REDRAW:
|
||||
redraw_down:
|
||||
fbcon_redraw(vc, p, b - 1, b - t - count,
|
||||
-count * vc->vc_cols);
|
||||
fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
||||
scr_memsetw((unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row *
|
||||
t),
|
||||
vc->vc_video_erase_char,
|
||||
vc->vc_size_row * count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
|
||||
int height, int width)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
if (fbcon_is_inactive(vc, info))
|
||||
return;
|
||||
|
||||
if (!width || !height)
|
||||
return;
|
||||
|
||||
/* Split blits that cross physical y_wrap case.
|
||||
* Pathological case involves 4 blits, better to use recursive
|
||||
* code rather than unrolled case
|
||||
*
|
||||
* Recursive invocations don't need to erase the cursor over and
|
||||
* over again, so we use fbcon_bmove_rec()
|
||||
*/
|
||||
fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
|
||||
p->vrows - p->yscroll);
|
||||
}
|
||||
|
||||
static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
|
||||
int dy, int dx, int height, int width, u_int y_break)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u_int b;
|
||||
|
||||
if (sy < y_break && sy + height > y_break) {
|
||||
b = y_break - sy;
|
||||
if (dy < sy) { /* Avoid trashing self */
|
||||
fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
|
||||
y_break);
|
||||
fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
|
||||
height - b, width, y_break);
|
||||
} else {
|
||||
fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
|
||||
height - b, width, y_break);
|
||||
fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
|
||||
y_break);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (dy < y_break && dy + height > y_break) {
|
||||
b = y_break - dy;
|
||||
if (dy < sy) { /* Avoid trashing self */
|
||||
fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
|
||||
y_break);
|
||||
fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
|
||||
height - b, width, y_break);
|
||||
} else {
|
||||
fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
|
||||
height - b, width, y_break);
|
||||
fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
|
||||
y_break);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
|
||||
height, width);
|
||||
}
|
||||
|
||||
static void updatescrollmode_accel(struct fbcon_display *p,
|
||||
struct fb_info *info,
|
||||
struct vc_data *vc)
|
||||
{
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
int cap = info->flags;
|
||||
u16 t = 0;
|
||||
int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
|
||||
info->fix.xpanstep);
|
||||
int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
|
||||
int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
|
||||
int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
|
||||
info->var.xres_virtual);
|
||||
int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
|
||||
divides(ypan, vc->vc_font.height) && vyres > yres;
|
||||
int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
|
||||
divides(ywrap, vc->vc_font.height) &&
|
||||
divides(vc->vc_font.height, vyres) &&
|
||||
divides(vc->vc_font.height, yres);
|
||||
int reading_fast = cap & FBINFO_READS_FAST;
|
||||
int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
|
||||
!(cap & FBINFO_HWACCEL_DISABLED);
|
||||
int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
|
||||
!(cap & FBINFO_HWACCEL_DISABLED);
|
||||
|
||||
if (good_wrap || good_pan) {
|
||||
if (reading_fast || fast_copyarea)
|
||||
p->scrollmode = good_wrap ?
|
||||
SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
|
||||
else
|
||||
p->scrollmode = good_wrap ? SCROLL_REDRAW :
|
||||
SCROLL_PAN_REDRAW;
|
||||
} else {
|
||||
if (reading_fast || (fast_copyarea && !fast_imageblit))
|
||||
p->scrollmode = SCROLL_MOVE;
|
||||
else
|
||||
p->scrollmode = SCROLL_REDRAW;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void updatescrollmode(struct fbcon_display *p,
|
||||
struct fb_info *info,
|
||||
struct vc_data *vc)
|
||||
|
@ -1507,6 +2005,9 @@ static void updatescrollmode(struct fbcon_display *p,
|
|||
p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
|
||||
if ((yres % fh) && (vyres % fh < yres % fh))
|
||||
p->vrows--;
|
||||
|
||||
/* update scrollmode in case hardware acceleration is used */
|
||||
updatescrollmode_accel(p, info, vc);
|
||||
}
|
||||
|
||||
#define PITCH(w) (((w) + 7) >> 3)
|
||||
|
@ -1664,7 +2165,21 @@ static int fbcon_switch(struct vc_data *vc)
|
|||
|
||||
updatescrollmode(p, info, vc);
|
||||
|
||||
scrollback_phys_max = 0;
|
||||
switch (fb_scrollmode(p)) {
|
||||
case SCROLL_WRAP_MOVE:
|
||||
scrollback_phys_max = p->vrows - vc->vc_rows;
|
||||
break;
|
||||
case SCROLL_PAN_MOVE:
|
||||
case SCROLL_PAN_REDRAW:
|
||||
scrollback_phys_max = p->vrows - 2 * vc->vc_rows;
|
||||
if (scrollback_phys_max < 0)
|
||||
scrollback_phys_max = 0;
|
||||
break;
|
||||
default:
|
||||
scrollback_phys_max = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
scrollback_max = 0;
|
||||
scrollback_current = 0;
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ struct fbcon_display {
|
|||
/* Filled in by the low-level console driver */
|
||||
const u_char *fontdata;
|
||||
int userfont; /* != 0 if fontdata kmalloc()ed */
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
|
||||
u_short scrollmode; /* Scroll Method, use fb_scrollmode() */
|
||||
#endif
|
||||
u_short inverse; /* != 0 text black on white as default */
|
||||
short yscroll; /* Hardware scrolling */
|
||||
int vrows; /* number of virtual rows */
|
||||
|
@ -51,6 +54,8 @@ struct fbcon_display {
|
|||
};
|
||||
|
||||
struct fbcon_ops {
|
||||
void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width);
|
||||
void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width);
|
||||
void (*putcs)(struct vc_data *vc, struct fb_info *info,
|
||||
|
@ -149,6 +154,73 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
|
|||
#define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
|
||||
#define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
|
||||
|
||||
/*
|
||||
* Scroll Method
|
||||
*/
|
||||
|
||||
/* There are several methods fbcon can use to move text around the screen:
|
||||
*
|
||||
* Operation Pan Wrap
|
||||
*---------------------------------------------
|
||||
* SCROLL_MOVE copyarea No No
|
||||
* SCROLL_PAN_MOVE copyarea Yes No
|
||||
* SCROLL_WRAP_MOVE copyarea No Yes
|
||||
* SCROLL_REDRAW imageblit No No
|
||||
* SCROLL_PAN_REDRAW imageblit Yes No
|
||||
* SCROLL_WRAP_REDRAW imageblit No Yes
|
||||
*
|
||||
* (SCROLL_WRAP_REDRAW is not implemented yet)
|
||||
*
|
||||
* In general, fbcon will choose the best scrolling
|
||||
* method based on the rule below:
|
||||
*
|
||||
* Pan/Wrap > accel imageblit > accel copyarea >
|
||||
* soft imageblit > (soft copyarea)
|
||||
*
|
||||
* Exception to the rule: Pan + accel copyarea is
|
||||
* preferred over Pan + accel imageblit.
|
||||
*
|
||||
* The above is typical for PCI/AGP cards. Unless
|
||||
* overridden, fbcon will never use soft copyarea.
|
||||
*
|
||||
* If you need to override the above rule, set the
|
||||
* appropriate flags in fb_info->flags. For example,
|
||||
* to prefer copyarea over imageblit, set
|
||||
* FBINFO_READS_FAST.
|
||||
*
|
||||
* Other notes:
|
||||
* + use the hardware engine to move the text
|
||||
* (hw-accelerated copyarea() and fillrect())
|
||||
* + use hardware-supported panning on a large virtual screen
|
||||
* + amifb can not only pan, but also wrap the display by N lines
|
||||
* (i.e. visible line i = physical line (i+N) % yres).
|
||||
* + read what's already rendered on the screen and
|
||||
* write it in a different place (this is cfb_copyarea())
|
||||
* + re-render the text to the screen
|
||||
*
|
||||
* Whether to use wrapping or panning can only be figured out at
|
||||
* runtime (when we know whether our font height is a multiple
|
||||
* of the pan/wrap step)
|
||||
*
|
||||
*/
|
||||
|
||||
#define SCROLL_MOVE 0x001
|
||||
#define SCROLL_PAN_MOVE 0x002
|
||||
#define SCROLL_WRAP_MOVE 0x003
|
||||
#define SCROLL_REDRAW 0x004
|
||||
#define SCROLL_PAN_REDRAW 0x005
|
||||
|
||||
static inline u_short fb_scrollmode(struct fbcon_display *fb)
|
||||
{
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
|
||||
return fb->scrollmode;
|
||||
#else
|
||||
/* hardcoded to SCROLL_REDRAW if acceleration was disabled. */
|
||||
return SCROLL_REDRAW;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FB_TILEBLITTING
|
||||
extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
|
||||
#endif
|
||||
|
|
|
@ -59,12 +59,31 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_copyarea area;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
|
||||
area.sx = sy * vc->vc_font.height;
|
||||
area.sy = vyres - ((sx + width) * vc->vc_font.width);
|
||||
area.dx = dy * vc->vc_font.height;
|
||||
area.dy = vyres - ((dx + width) * vc->vc_font.width);
|
||||
area.width = height * vc->vc_font.height;
|
||||
area.height = width * vc->vc_font.width;
|
||||
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
|
||||
static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_fillrect region;
|
||||
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
||||
u32 vyres = info->var.yres;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
|
||||
region.color = attr_bgcol_ec(bgshift,vc,info);
|
||||
region.dx = sy * vc->vc_font.height;
|
||||
|
@ -121,7 +140,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
|
|||
u32 cnt, pitch, size;
|
||||
u32 attribute = get_attribute(info, scr_readw(s));
|
||||
u8 *dst, *buf = NULL;
|
||||
u32 vyres = info->var.yres;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
@ -210,7 +229,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|||
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
|
||||
int err = 1, dx, dy;
|
||||
char *src;
|
||||
u32 vyres = info->var.yres;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
@ -368,7 +387,7 @@ static int ccw_update_start(struct fb_info *info)
|
|||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u32 yoffset;
|
||||
u32 vyres = info->var.yres;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
int err;
|
||||
|
||||
yoffset = (vyres - info->var.yres) - ops->var.xoffset;
|
||||
|
@ -383,6 +402,7 @@ static int ccw_update_start(struct fb_info *info)
|
|||
|
||||
void fbcon_rotate_ccw(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->bmove = ccw_bmove;
|
||||
ops->clear = ccw_clear;
|
||||
ops->putcs = ccw_putcs;
|
||||
ops->clear_margins = ccw_clear_margins;
|
||||
|
|
|
@ -44,12 +44,31 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_copyarea area;
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
|
||||
area.sx = vxres - ((sy + height) * vc->vc_font.height);
|
||||
area.sy = sx * vc->vc_font.width;
|
||||
area.dx = vxres - ((dy + height) * vc->vc_font.height);
|
||||
area.dy = dx * vc->vc_font.width;
|
||||
area.width = height * vc->vc_font.height;
|
||||
area.height = width * vc->vc_font.width;
|
||||
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
|
||||
static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_fillrect region;
|
||||
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
||||
u32 vxres = info->var.xres;
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
|
||||
region.color = attr_bgcol_ec(bgshift,vc,info);
|
||||
region.dx = vxres - ((sy + height) * vc->vc_font.height);
|
||||
|
@ -106,7 +125,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
|
|||
u32 cnt, pitch, size;
|
||||
u32 attribute = get_attribute(info, scr_readw(s));
|
||||
u8 *dst, *buf = NULL;
|
||||
u32 vxres = info->var.xres;
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
@ -193,7 +212,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|||
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
|
||||
int err = 1, dx, dy;
|
||||
char *src;
|
||||
u32 vxres = info->var.xres;
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
@ -350,7 +369,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|||
static int cw_update_start(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u32 vxres = info->var.xres;
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
u32 xoffset;
|
||||
int err;
|
||||
|
||||
|
@ -366,6 +385,7 @@ static int cw_update_start(struct fb_info *info)
|
|||
|
||||
void fbcon_rotate_cw(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->bmove = cw_bmove;
|
||||
ops->clear = cw_clear;
|
||||
ops->putcs = cw_putcs;
|
||||
ops->clear_margins = cw_clear_margins;
|
||||
|
|
|
@ -11,6 +11,15 @@
|
|||
#ifndef _FBCON_ROTATE_H
|
||||
#define _FBCON_ROTATE_H
|
||||
|
||||
#define GETVYRES(s,i) ({ \
|
||||
(fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE) ? \
|
||||
(i)->var.yres : (i)->var.yres_virtual; })
|
||||
|
||||
#define GETVXRES(s,i) ({ \
|
||||
(fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
|
||||
(i)->var.xres : (i)->var.xres_virtual; })
|
||||
|
||||
|
||||
static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
|
||||
{
|
||||
u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
|
||||
|
|
|
@ -44,13 +44,33 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_copyarea area;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
|
||||
area.sy = vyres - ((sy + height) * vc->vc_font.height);
|
||||
area.sx = vxres - ((sx + width) * vc->vc_font.width);
|
||||
area.dy = vyres - ((dy + height) * vc->vc_font.height);
|
||||
area.dx = vxres - ((dx + width) * vc->vc_font.width);
|
||||
area.height = height * vc->vc_font.height;
|
||||
area.width = width * vc->vc_font.width;
|
||||
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
|
||||
static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_fillrect region;
|
||||
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
||||
u32 vyres = info->var.yres;
|
||||
u32 vxres = info->var.xres;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
|
||||
region.color = attr_bgcol_ec(bgshift,vc,info);
|
||||
region.dy = vyres - ((sy + height) * vc->vc_font.height);
|
||||
|
@ -142,8 +162,8 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
|
|||
u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
|
||||
u32 attribute = get_attribute(info, scr_readw(s));
|
||||
u8 *dst, *buf = NULL;
|
||||
u32 vyres = info->var.yres;
|
||||
u32 vxres = info->var.xres;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
@ -239,8 +259,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
|||
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
|
||||
int err = 1, dx, dy;
|
||||
char *src;
|
||||
u32 vyres = info->var.yres;
|
||||
u32 vxres = info->var.xres;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
@ -390,8 +410,8 @@ static int ud_update_start(struct fb_info *info)
|
|||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
int xoffset, yoffset;
|
||||
u32 vyres = info->var.yres;
|
||||
u32 vxres = info->var.xres;
|
||||
u32 vyres = GETVYRES(ops->p, info);
|
||||
u32 vxres = GETVXRES(ops->p, info);
|
||||
int err;
|
||||
|
||||
xoffset = vxres - info->var.xres - ops->var.xoffset;
|
||||
|
@ -409,6 +429,7 @@ static int ud_update_start(struct fb_info *info)
|
|||
|
||||
void fbcon_rotate_ud(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->bmove = ud_bmove;
|
||||
ops->clear = ud_clear;
|
||||
ops->putcs = ud_putcs;
|
||||
ops->clear_margins = ud_clear_margins;
|
||||
|
|
|
@ -16,6 +16,21 @@
|
|||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
|
||||
static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fb_tilearea area;
|
||||
|
||||
area.sx = sx;
|
||||
area.sy = sy;
|
||||
area.dx = dx;
|
||||
area.dy = dy;
|
||||
area.height = height;
|
||||
area.width = width;
|
||||
|
||||
info->tileops->fb_tilecopy(info, &area);
|
||||
}
|
||||
|
||||
static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
|
@ -118,6 +133,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
|
|||
struct fb_tilemap map;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
ops->bmove = tile_bmove;
|
||||
ops->clear = tile_clear;
|
||||
ops->putcs = tile_putcs;
|
||||
ops->clear_margins = tile_clear_margins;
|
||||
|
|
|
@ -505,15 +505,15 @@ void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
|
|||
}
|
||||
|
||||
/**
|
||||
* xxxfb_copyarea - OBSOLETE function.
|
||||
* xxxfb_copyarea - REQUIRED function. Can use generic routines if
|
||||
* non acclerated hardware and packed pixel based.
|
||||
* Copies one area of the screen to another area.
|
||||
* Will be deleted in a future version
|
||||
*
|
||||
* @info: frame buffer structure that represents a single frame buffer
|
||||
* @area: Structure providing the data to copy the framebuffer contents
|
||||
* from one region to another.
|
||||
*
|
||||
* This drawing operation copied a rectangular area from one area of the
|
||||
* This drawing operation copies a rectangular area from one area of the
|
||||
* screen to another area.
|
||||
*/
|
||||
void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
|
||||
|
@ -645,9 +645,9 @@ static const struct fb_ops xxxfb_ops = {
|
|||
.fb_setcolreg = xxxfb_setcolreg,
|
||||
.fb_blank = xxxfb_blank,
|
||||
.fb_pan_display = xxxfb_pan_display,
|
||||
.fb_fillrect = xxxfb_fillrect, /* Needed !!! */
|
||||
.fb_copyarea = xxxfb_copyarea, /* Obsolete */
|
||||
.fb_imageblit = xxxfb_imageblit, /* Needed !!! */
|
||||
.fb_fillrect = xxxfb_fillrect, /* Needed !!! */
|
||||
.fb_copyarea = xxxfb_copyarea, /* Needed !!! */
|
||||
.fb_imageblit = xxxfb_imageblit, /* Needed !!! */
|
||||
.fb_cursor = xxxfb_cursor, /* Optional !!! */
|
||||
.fb_sync = xxxfb_sync,
|
||||
.fb_ioctl = xxxfb_ioctl,
|
||||
|
|
|
@ -262,7 +262,7 @@ struct fb_ops {
|
|||
|
||||
/* Draws a rectangle */
|
||||
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
|
||||
/* Copy data from area to another. Obsolete. */
|
||||
/* Copy data from area to another */
|
||||
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
|
||||
/* Draws a image to the display */
|
||||
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
|
||||
|
|
Loading…
Reference in New Issue