Merge branch '00.06-gr-ampere' of https://gitlab.freedesktop.org/skeggsb/nouveau into drm-next

This is the pull request for a whole bunch of fixes and prep-work that
was done to support Ampere acceleration prior to GSP-RM being
available.  It uses the ACR firmware released by NVIDIA in
linux-firmware, as we do on earlier GPUs.  The work to support running
on top of GSP-RM also heavily depends on various pieces of this
series.

In addition to the new HW support, general stability of the driver
should be improved, especially around recovering HW from bugs that can
be generated by userspace driver components.

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Ben Skeggs <bskeggs@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/CABDvA==s+nZD0n7CuRWLPE=Pj+02CN13r+ZQJxoHQ_EmR+o=XQ@mail.gmail.com
This commit is contained in:
Dave Airlie 2022-11-09 10:48:44 +10:00
commit a143bc517b
407 changed files with 15807 additions and 13303 deletions

View file

@ -54,10 +54,6 @@ nouveau-y += nouveau_bios.o
nouveau-y += nouveau_connector.o
nouveau-y += nouveau_display.o
nouveau-y += nouveau_dp.o
nouveau-y += nouveau_fbcon.o
nouveau-y += nv04_fbcon.o
nouveau-y += nv50_fbcon.o
nouveau-y += nvc0_fbcon.o
include $(src)/dispnv04/Kbuild
include $(src)/dispnv50/Kbuild

View file

@ -23,6 +23,7 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_vblank.h>
@ -37,7 +38,6 @@
#include "nouveau_crtc.h"
#include "hw.h"
#include "nvreg.h"
#include "nouveau_fbcon.h"
#include "disp.h"
#include "nouveau_dma.h"
@ -761,7 +761,8 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
nouveau_bo_unmap(nv_crtc->cursor.nvbo);
nouveau_bo_unpin(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
nvif_notify_dtor(&nv_crtc->vblank);
nvif_event_dtor(&nv_crtc->vblank);
nvif_head_dtor(&nv_crtc->head);
kfree(nv_crtc);
}
@ -914,14 +915,6 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int x, int y, enum mode_set_atomic state)
{
struct nouveau_drm *drm = nouveau_drm(crtc->dev);
struct drm_device *dev = drm->dev;
if (state == ENTER_ATOMIC_MODE_SET)
nouveau_fbcon_accel_save_disable(dev);
else
nouveau_fbcon_accel_restore(dev);
return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
}
@ -1080,10 +1073,10 @@ nv04_finish_page_flip(struct nouveau_channel *chan,
}
int
nv04_flip_complete(struct nvif_notify *notify)
nv04_flip_complete(struct nvif_event *event, void *argv, u32 argc)
{
struct nouveau_cli *cli = (void *)notify->object->client;
struct nouveau_drm *drm = cli->drm;
struct nv04_display *disp = container_of(event, typeof(*disp), flip);
struct nouveau_drm *drm = disp->drm;
struct nouveau_channel *chan = drm->channel;
struct nv04_page_flip_state state;
@ -1094,7 +1087,7 @@ nv04_flip_complete(struct nvif_notify *notify)
state.bpp / 8);
}
return NVIF_NOTIFY_KEEP;
return NVIF_EVENT_KEEP;
}
static int
@ -1279,13 +1272,13 @@ static const struct drm_plane_funcs nv04_primary_plane_funcs = {
DRM_PLANE_NON_ATOMIC_FUNCS,
};
static int nv04_crtc_vblank_handler(struct nvif_notify *notify)
static int
nv04_crtc_vblank_handler(struct nvif_event *event, void *repv, u32 repc)
{
struct nouveau_crtc *nv_crtc =
container_of(notify, struct nouveau_crtc, vblank);
struct nouveau_crtc *nv_crtc = container_of(event, struct nouveau_crtc, vblank);
drm_crtc_handle_vblank(&nv_crtc->base);
return NVIF_NOTIFY_KEEP;
return NVIF_EVENT_KEEP;
}
int
@ -1341,14 +1334,10 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
nv04_cursor_init(nv_crtc);
ret = nvif_notify_ctor(&disp->disp.object, "kmsVbl", nv04_crtc_vblank_handler,
false, NV04_DISP_NTFY_VBLANK,
&(struct nvif_notify_head_req_v0) {
.head = nv_crtc->index,
},
sizeof(struct nvif_notify_head_req_v0),
sizeof(struct nvif_notify_head_rep_v0),
&nv_crtc->vblank);
ret = nvif_head_ctor(&disp->disp, nv_crtc->base.name, nv_crtc->index, &nv_crtc->head);
if (ret)
return ret;
return ret;
return nvif_head_vblank_event_ctor(&nv_crtc->head, "kmsVbl", nv04_crtc_vblank_handler,
false, &nv_crtc->vblank);
}

View file

@ -61,7 +61,7 @@ nv04_display_fini(struct drm_device *dev, bool runtime, bool suspend)
struct drm_crtc *crtc;
/* Disable flip completion events. */
nvif_notify_put(&disp->flip);
nvif_event_block(&disp->flip);
/* Disable vblank interrupts. */
NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
@ -121,7 +121,7 @@ nv04_display_init(struct drm_device *dev, bool resume, bool runtime)
encoder->enc_save(&encoder->base.base);
/* Enable flip completion events. */
nvif_notify_get(&disp->flip);
nvif_event_allow(&disp->flip);
if (!resume)
return 0;
@ -202,7 +202,7 @@ nv04_display_destroy(struct drm_device *dev)
nouveau_hw_save_vga_fonts(dev, 0);
nvif_notify_dtor(&disp->flip);
nvif_event_dtor(&disp->flip);
nouveau_display(dev)->priv = NULL;
vfree(disp);
@ -227,6 +227,8 @@ nv04_display_create(struct drm_device *dev)
if (!disp)
return -ENOMEM;
disp->drm = drm;
nvif_object_map(&drm->client.device.object, NULL, 0);
nouveau_display(dev)->priv = disp;
@ -239,9 +241,10 @@ nv04_display_create(struct drm_device *dev)
/* Request page flip completion event. */
if (drm->channel) {
nvif_notify_ctor(&drm->channel->nvsw, "kmsFlip", nv04_flip_complete,
false, NV04_NVSW_NTFY_UEVENT,
NULL, 0, 0, &disp->flip);
ret = nvif_event_ctor(&drm->channel->nvsw, "kmsFlip", 0, nv04_flip_complete,
true, NULL, 0, &disp->flip);
if (ret)
return ret;
}
nouveau_hw_save_vga_fonts(dev, 1);

View file

@ -6,6 +6,8 @@
#include "nouveau_display.h"
#include <nvif/event.h>
struct nouveau_encoder;
enum nv04_fp_display_regs {
@ -84,7 +86,8 @@ struct nv04_display {
uint32_t saved_vga_font[4][16384];
uint32_t dac_users[4];
struct nouveau_bo *image[2];
struct nvif_notify flip;
struct nvif_event flip;
struct nouveau_drm *drm;
};
static inline struct nv04_display *
@ -179,5 +182,5 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table,
);
}
int nv04_flip_complete(struct nvif_notify *);
int nv04_flip_complete(struct nvif_event *, void *, u32);
#endif

View file

@ -463,7 +463,7 @@ void nv50_crc_atomic_set(struct nv50_head *head,
if (!outp)
return;
func->set_src(head, outp->or, nv50_crc_source_type(outp, asyh->crc.src),
func->set_src(head, outp->outp.or.id, nv50_crc_source_type(outp, asyh->crc.src),
&crc->ctx[crc->ctx_idx]);
}

View file

@ -46,8 +46,8 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
#include <nvif/cl5070.h>
#include <nvif/event.h>
#include <nvif/if0012.h>
#include <nvif/if0014.h>
#include <nvif/timer.h>
@ -64,7 +64,6 @@
#include "nouveau_connector.h"
#include "nouveau_encoder.h"
#include "nouveau_fence.h"
#include "nouveau_fbcon.h"
#include <subdev/bios/dp.h>
@ -317,52 +316,6 @@ nv50_outp_dump_caps(struct nouveau_drm *drm,
outp->base.base.name, outp->caps.dp_interlace);
}
static void
nv50_outp_release(struct nouveau_encoder *nv_encoder)
{
struct nv50_disp *disp = nv50_disp(nv_encoder->base.base.dev);
struct {
struct nv50_disp_mthd_v1 base;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_RELEASE,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = nv_encoder->dcb->hashm,
};
nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
nv_encoder->or = -1;
nv_encoder->link = 0;
}
static int
nv50_outp_acquire(struct nouveau_encoder *nv_encoder, bool hda)
{
struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
struct nv50_disp *disp = nv50_disp(drm->dev);
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_acquire_v0 info;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_ACQUIRE,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = nv_encoder->dcb->hashm,
.info.hda = hda,
};
int ret;
ret = nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
if (ret) {
NV_ERROR(drm, "error acquiring output path: %d\n", ret);
return ret;
}
nv_encoder->or = args.info.or;
nv_encoder->link = args.info.link;
return 0;
}
static int
nv50_outp_atomic_check_view(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
@ -489,9 +442,9 @@ nv50_dac_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st
struct nv50_core *core = nv50_disp(encoder->dev)->core;
const u32 ctrl = NVDEF(NV507D, DAC_SET_CONTROL, OWNER, NONE);
core->func->dac->ctrl(core, nv_encoder->or, ctrl, NULL);
core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL);
nv_encoder->crtc = NULL;
nv50_outp_release(nv_encoder);
nvif_outp_release(&nv_encoder->outp);
}
static void
@ -516,9 +469,9 @@ nv50_dac_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, PROTOCOL, RGB_CRT);
nv50_outp_acquire(nv_encoder, false);
nvif_outp_acquire_rgb_crt(&nv_encoder->outp);
core->func->dac->ctrl(core, nv_encoder->or, ctrl, asyh);
core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh);
asyh->or.depth = 0;
nv_encoder->crtc = &nv_crtc->base;
@ -634,7 +587,7 @@ nv50_audio_component_get_eld(struct device *kdev, int port, int dev_id,
nv_connector = nouveau_connector(nv_encoder->audio.connector);
nv_crtc = nouveau_crtc(nv_encoder->crtc);
if (!nv_crtc || nv_encoder->or != port || nv_crtc->index != dev_id)
if (!nv_crtc || nv_encoder->outp.or.id != port || nv_crtc->index != dev_id)
continue;
*enabled = nv_encoder->audio.enabled;
@ -718,33 +671,37 @@ nv50_audio_component_fini(struct nouveau_drm *drm)
/******************************************************************************
* Audio
*****************************************************************************/
static bool
nv50_audio_supported(struct drm_encoder *encoder)
{
struct nv50_disp *disp = nv50_disp(encoder->dev);
if (disp->disp->object.oclass <= GT200_DISP ||
disp->disp->object.oclass == GT206_DISP)
return false;
return true;
}
static void
nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
{
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_sor_hda_eld_v0 eld;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
(0x0100 << nv_crtc->index),
};
struct nvif_outp *outp = &nv_encoder->outp;
if (!nv50_audio_supported(encoder))
return;
mutex_lock(&drm->audio.lock);
if (nv_encoder->audio.enabled) {
nv_encoder->audio.enabled = false;
nv_encoder->audio.connector = NULL;
nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, NULL, 0);
}
mutex_unlock(&drm->audio.lock);
nv50_audio_component_eld_notify(drm->audio.component, nv_encoder->or,
nv_crtc->index);
nv50_audio_component_eld_notify(drm->audio.component, outp->or.id, nv_crtc->index);
}
static void
@ -754,159 +711,105 @@ nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
{
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
struct __packed {
struct {
struct nv50_disp_mthd_v1 mthd;
struct nv50_disp_sor_hda_eld_v0 eld;
} base;
u8 data[sizeof(nv_connector->base.eld)];
} args = {
.base.mthd.version = 1,
.base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
.base.mthd.hasht = nv_encoder->dcb->hasht,
.base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
(0x0100 << nv_crtc->index),
};
struct nvif_outp *outp = &nv_encoder->outp;
if (!drm_detect_monitor_audio(nv_connector->edid))
if (!nv50_audio_supported(encoder) || !drm_detect_monitor_audio(nv_connector->edid))
return;
mutex_lock(&drm->audio.lock);
memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
nvif_mthd(&disp->disp->object, 0, &args,
sizeof(args.base) + drm_eld_size(args.data));
nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, nv_connector->base.eld,
drm_eld_size(nv_connector->base.eld));
nv_encoder->audio.enabled = true;
nv_encoder->audio.connector = &nv_connector->base;
mutex_unlock(&drm->audio.lock);
nv50_audio_component_eld_notify(drm->audio.component, nv_encoder->or,
nv_crtc->index);
nv50_audio_component_eld_notify(drm->audio.component, outp->or.id, nv_crtc->index);
}
/******************************************************************************
* HDMI
*****************************************************************************/
static void
nv50_hdmi_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_sor_hdmi_pwr_v0 pwr;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
(0x0100 << nv_crtc->index),
};
nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
}
static void
nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
struct nouveau_connector *nv_connector, struct drm_atomic_state *state,
struct drm_display_mode *mode)
struct drm_display_mode *mode, bool hda)
{
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_sor_hdmi_pwr_v0 pwr;
u8 infoframes[2 * 17]; /* two frames, up to 17 bytes each */
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
(0x0100 << nv_crtc->index),
.pwr.state = 1,
.pwr.rekey = 56, /* binary driver, and tegra, constant */
};
struct drm_hdmi_info *hdmi;
struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi;
union hdmi_infoframe infoframe;
const u8 rekey = 56; /* binary driver, and tegra, constant */
u8 config, scdc = 0;
u32 max_ac_packet;
union hdmi_infoframe avi_frame;
union hdmi_infoframe vendor_frame;
bool high_tmds_clock_ratio = false, scrambling = false;
u8 config;
int ret;
int size;
if (!drm_detect_hdmi_monitor(nv_connector->edid))
return;
hdmi = &nv_connector->base.display_info.hdmi;
ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi,
&nv_connector->base, mode);
if (!ret) {
drm_hdmi_avi_infoframe_quant_range(&avi_frame.avi,
&nv_connector->base, mode,
HDMI_QUANTIZATION_RANGE_FULL);
/* We have an AVI InfoFrame, populate it to the display */
args.pwr.avi_infoframe_length
= hdmi_infoframe_pack(&avi_frame, args.infoframes, 17);
}
ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi,
&nv_connector->base, mode);
if (!ret) {
/* We have a Vendor InfoFrame, populate it to the display */
args.pwr.vendor_infoframe_length
= hdmi_infoframe_pack(&vendor_frame,
args.infoframes
+ args.pwr.avi_infoframe_length,
17);
}
struct {
struct nvif_outp_infoframe_v0 infoframe;
u8 data[17];
} args;
int ret, size;
max_ac_packet = mode->htotal - mode->hdisplay;
max_ac_packet -= args.pwr.rekey;
max_ac_packet -= rekey;
max_ac_packet -= 18; /* constant from tegra */
args.pwr.max_ac_packet = max_ac_packet / 32;
max_ac_packet /= 32;
if (hdmi->scdc.scrambling.supported) {
high_tmds_clock_ratio = mode->clock > 340000;
scrambling = high_tmds_clock_ratio ||
hdmi->scdc.scrambling.low_rates;
const bool high_tmds_clock_ratio = mode->clock > 340000;
ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &config);
if (ret < 0) {
NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret);
return;
}
config &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE);
if (high_tmds_clock_ratio || hdmi->scdc.scrambling.low_rates)
config |= SCDC_SCRAMBLING_ENABLE;
if (high_tmds_clock_ratio)
config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, config);
if (ret < 0)
NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n",
config, ret);
if (high_tmds_clock_ratio || hdmi->scdc.scrambling.low_rates)
scdc |= NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_SCRAMBLE;
if (high_tmds_clock_ratio)
scdc |= NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_DIV_BY_4;
}
args.pwr.scdc =
NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE * scrambling |
NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 * high_tmds_clock_ratio;
ret = nvif_outp_acquire_tmds(&nv_encoder->outp, nv_crtc->index, true,
max_ac_packet, rekey, scdc, hda);
if (ret)
return;
size = sizeof(args.base)
+ sizeof(args.pwr)
+ args.pwr.avi_infoframe_length
+ args.pwr.vendor_infoframe_length;
nvif_mthd(&disp->disp->object, 0, &args, size);
/* AVI InfoFrame. */
args.infoframe.version = 0;
args.infoframe.head = nv_crtc->index;
if (!drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi, &nv_connector->base, mode)) {
drm_hdmi_avi_infoframe_quant_range(&infoframe.avi, &nv_connector->base, mode,
HDMI_QUANTIZATION_RANGE_FULL);
size = hdmi_infoframe_pack(&infoframe, args.data, 17);
} else {
size = 0;
}
nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_AVI, &args.infoframe, size);
/* Vendor InfoFrame. */
if (!drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi,
&nv_connector->base, mode))
size = hdmi_infoframe_pack(&infoframe, args.data, 17);
else
size = 0;
nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, &args.infoframe, size);
nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode);
/* If SCDC is supported by the downstream monitor, update
* divider / scrambling settings to what we programmed above.
*/
if (!hdmi->scdc.scrambling.supported)
return;
ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &config);
if (ret < 0) {
NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret);
return;
}
config &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE);
config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 * high_tmds_clock_ratio;
config |= SCDC_SCRAMBLING_ENABLE * scrambling;
ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, config);
if (ret < 0)
NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n",
config, ret);
}
/******************************************************************************
@ -979,16 +882,6 @@ nv50_msto_prepare(struct drm_atomic_state *state,
struct nv50_mstc *mstc = msto->mstc;
struct nv50_mstm *mstm = mstc->mstm;
struct drm_dp_mst_atomic_payload *payload;
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_sor_dp_mst_vcpi_v0 vcpi;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI,
.base.hasht = mstm->outp->dcb->hasht,
.base.hashm = (0xf0ff & mstm->outp->dcb->hashm) |
(0x0100 << msto->head->base.index),
};
NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name);
@ -997,22 +890,16 @@ nv50_msto_prepare(struct drm_atomic_state *state,
// TODO: Figure out if we want to do a better job of handling VCPI allocation failures here?
if (msto->disabled) {
drm_dp_remove_payload(mgr, mst_state, payload);
nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0);
} else {
if (msto->enabled)
drm_dp_add_payload_part1(mgr, mst_state, payload);
args.vcpi.start_slot = payload->vc_start_slot;
args.vcpi.num_slots = payload->time_slots;
args.vcpi.pbn = payload->pbn;
args.vcpi.aligned_pbn = payload->time_slots * mst_state->pbn_div;
nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index,
payload->vc_start_slot, payload->time_slots,
payload->pbn, payload->time_slots * mst_state->pbn_div);
}
NV_ATOMIC(drm, "%s: %s: %02x %02x %04x %04x\n",
msto->encoder.name, msto->head->base.base.name,
args.vcpi.start_slot, args.vcpi.num_slots,
args.vcpi.pbn, args.vcpi.aligned_pbn);
nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args));
}
static int
@ -1107,10 +994,12 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
if (WARN_ON(!mstc))
return;
if (!mstm->links++)
nv50_outp_acquire(mstm->outp, false /*XXX: MST audio.*/);
if (!mstm->links++) {
/*XXX: MST audio. */
nvif_outp_acquire_dp(&mstm->outp->outp, mstm->outp->dp.dpcd, 0, 0, false, true);
}
if (mstm->outp->link & 1)
if (mstm->outp->outp.or.link & 1)
proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_A;
else
proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_B;
@ -1405,7 +1294,7 @@ nv50_mstm_prepare(struct drm_atomic_state *state,
if (mstm->disabled) {
if (!mstm->links)
nv50_outp_release(mstm->outp);
nvif_outp_release(&mstm->outp->outp);
mstm->disabled = false;
}
}
@ -1473,26 +1362,6 @@ nv50_mstm_remove(struct nv50_mstm *mstm)
drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false);
}
static int
nv50_mstm_enable(struct nv50_mstm *mstm, int state)
{
struct nouveau_encoder *outp = mstm->outp;
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_sor_dp_mst_link_v0 mst;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_LINK,
.base.hasht = outp->dcb->hasht,
.base.hashm = outp->dcb->hashm,
.mst.state = state,
};
struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev);
struct nvif_object *disp = &drm->display->disp.object;
return nvif_mthd(disp, 0, &args, sizeof(args));
}
int
nv50_mstm_detect(struct nouveau_encoder *outp)
{
@ -1513,16 +1382,10 @@ nv50_mstm_detect(struct nouveau_encoder *outp)
return ret;
/* And start enabling */
ret = nv50_mstm_enable(mstm, true);
ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, true);
if (ret)
return ret;
ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, true);
if (ret) {
nv50_mstm_enable(mstm, false);
return ret;
}
mstm->is_mst = true;
return 1;
}
@ -1623,7 +1486,7 @@ nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head,
asyh->or.depth = depth;
}
core->func->sor->ctrl(core, nv_encoder->or, nv_encoder->ctrl, asyh);
core->func->sor->ctrl(core, nv_encoder->outp.or.id, nv_encoder->ctrl, asyh);
}
/* TODO: Should we extend this to PWM-only backlights?
@ -1666,8 +1529,7 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st
nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0);
nv50_audio_disable(encoder, nv_crtc);
nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc);
nv50_outp_release(nv_encoder);
nvif_outp_release(&nv_encoder->outp);
nv_encoder->crtc = NULL;
}
@ -1679,16 +1541,8 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
struct nv50_head_atom *asyh =
nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base));
struct drm_display_mode *mode = &asyh->state.adjusted_mode;
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_sor_lvds_script_v0 lvds;
} lvds = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = nv_encoder->dcb->hashm,
};
struct nv50_disp *disp = nv50_disp(encoder->dev);
struct nvif_outp *outp = &nv_encoder->outp;
struct drm_device *dev = encoder->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_connector *nv_connector;
@ -1696,7 +1550,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
struct nouveau_backlight *backlight;
#endif
struct nvbios *bios = &drm->vbios;
bool hda = false;
bool lvds_dual = false, lvds_8bpc = false, hda = false;
u8 proto = NV507D_SOR_SET_CONTROL_PROTOCOL_CUSTOM;
u8 depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT;
@ -1707,11 +1561,16 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
disp->disp->object.oclass >= GF110_DISP) &&
drm_detect_monitor_audio(nv_connector->edid))
hda = true;
nv50_outp_acquire(nv_encoder, hda);
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
if (nv_encoder->link & 1) {
if (disp->disp->object.oclass == NV50_DISP ||
!drm_detect_hdmi_monitor(nv_connector->edid))
nvif_outp_acquire_tmds(outp, nv_crtc->index, false, 0, 0, 0, false);
else
nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda);
if (nv_encoder->outp.or.link & 1) {
proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_A;
/* Only enable dual-link if:
* - Need to (i.e. rate > 165MHz)
@ -1726,44 +1585,41 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
} else {
proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_B;
}
nv50_hdmi_enable(&nv_encoder->base.base, nv_crtc, nv_connector, state, mode);
break;
case DCB_OUTPUT_LVDS:
proto = NV507D_SOR_SET_CONTROL_PROTOCOL_LVDS_CUSTOM;
if (bios->fp_no_ddc) {
if (bios->fp.dual_link)
lvds.lvds.script |= 0x0100;
if (bios->fp.if_is_24bit)
lvds.lvds.script |= 0x0200;
lvds_dual = bios->fp.dual_link;
lvds_8bpc = bios->fp.if_is_24bit;
} else {
if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
if (((u8 *)nv_connector->edid)[121] == 2)
lvds.lvds.script |= 0x0100;
lvds_dual = true;
} else
if (mode->clock >= bios->fp.duallink_transition_clk) {
lvds.lvds.script |= 0x0100;
lvds_dual = true;
}
if (lvds.lvds.script & 0x0100) {
if (lvds_dual) {
if (bios->fp.strapless_is_24bit & 2)
lvds.lvds.script |= 0x0200;
lvds_8bpc = true;
} else {
if (bios->fp.strapless_is_24bit & 1)
lvds.lvds.script |= 0x0200;
lvds_8bpc = true;
}
if (asyh->or.bpc == 8)
lvds.lvds.script |= 0x0200;
lvds_8bpc = true;
}
nvif_mthd(&disp->disp->object, 0, &lvds, sizeof(lvds));
nvif_outp_acquire_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc);
break;
case DCB_OUTPUT_DP:
nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, hda, false);
depth = nv50_dp_bpc_to_depth(asyh->or.bpc);
if (nv_encoder->link & 1)
if (nv_encoder->outp.or.link & 1)
proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_A;
else
proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_B;
@ -1921,9 +1777,9 @@ nv50_pior_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *s
struct nv50_core *core = nv50_disp(encoder->dev)->core;
const u32 ctrl = NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, NONE);
core->func->pior->ctrl(core, nv_encoder->or, ctrl, NULL);
core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL);
nv_encoder->crtc = NULL;
nv50_outp_release(nv_encoder);
nvif_outp_release(&nv_encoder->outp);
}
static void
@ -1944,8 +1800,6 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
break;
}
nv50_outp_acquire(nv_encoder, false);
switch (asyh->or.bpc) {
case 10: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_30_444; break;
case 8: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_24_444; break;
@ -1955,15 +1809,19 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
nvif_outp_acquire_tmds(&nv_encoder->outp, false, false, 0, 0, 0, false);
break;
case DCB_OUTPUT_DP:
ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
nvif_outp_acquire_dp(&nv_encoder->outp, nv_encoder->dp.dpcd, 0, 0, false, false);
break;
default:
BUG();
break;
}
core->func->pior->ctrl(core, nv_encoder->or, ctrl, asyh);
core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh);
nv_encoder->crtc = &nv_crtc->base;
}
@ -2587,7 +2445,7 @@ nv50_disp_atomic_state_alloc(struct drm_device *dev)
static const struct drm_mode_config_funcs
nv50_disp_func = {
.fb_create = nouveau_user_framebuffer_create,
.output_poll_changed = nouveau_fbcon_output_poll_changed,
.output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = nv50_disp_atomic_check,
.atomic_commit = nv50_disp_atomic_commit,
.atomic_state_alloc = nv50_disp_atomic_state_alloc,

View file

@ -517,7 +517,8 @@ nv50_head_destroy(struct drm_crtc *crtc)
{
struct nv50_head *head = nv50_head(crtc);
nvif_notify_dtor(&head->base.vblank);
nvif_event_dtor(&head->base.vblank);
nvif_head_dtor(&head->base.head);
nv50_lut_fini(&head->olut);
drm_crtc_cleanup(crtc);
kfree(head);
@ -554,15 +555,15 @@ nvd9_head_func = {
.late_register = nv50_head_late_register,
};
static int nv50_head_vblank_handler(struct nvif_notify *notify)
static int
nv50_head_vblank_handler(struct nvif_event *event, void *repv, u32 repc)
{
struct nouveau_crtc *nv_crtc =
container_of(notify, struct nouveau_crtc, vblank);
struct nouveau_crtc *nv_crtc = container_of(event, struct nouveau_crtc, vblank);
if (drm_crtc_handle_vblank(&nv_crtc->base))
nv50_crc_handle_vblank(nv50_head(&nv_crtc->base));
return NVIF_NOTIFY_KEEP;
return NVIF_EVENT_KEEP;
}
struct nv50_head *
@ -624,14 +625,12 @@ nv50_head_create(struct drm_device *dev, int index)
}
}
ret = nvif_notify_ctor(&disp->disp->object, "kmsVbl", nv50_head_vblank_handler,
false, NV04_DISP_NTFY_VBLANK,
&(struct nvif_notify_head_req_v0) {
.head = nv_crtc->index,
},
sizeof(struct nvif_notify_head_req_v0),
sizeof(struct nvif_notify_head_rep_v0),
&nv_crtc->vblank);
ret = nvif_head_ctor(disp->disp, head->base.base.name, head->base.index, &head->base.head);
if (ret)
return ERR_PTR(ret);
ret = nvif_head_vblank_event_ctor(&head->base.head, "kmsVbl", nv50_head_vblank_handler,
false, &nv_crtc->vblank);
if (ret)
return ERR_PTR(ret);

View file

@ -39,6 +39,23 @@ struct wpr_header_v1 {
void wpr_header_v1_dump(struct nvkm_subdev *, const struct wpr_header_v1 *);
struct wpr_generic_header {
#define WPR_GENERIC_HEADER_ID_LSF_UCODE_DESC 1
#define WPR_GENERIC_HEADER_ID_LSF_WPR_HEADER 2
#define WPR_GENERIC_HEADER_ID_LSF_SHARED_SUB_WPR 3
#define WPR_GENERIC_HEADER_ID_LSF_LSB_HEADER 4
u16 identifier;
u16 version;
u32 size;
};
struct wpr_header_v2 {
struct wpr_generic_header hdr;
struct wpr_header_v1 wpr;
};
void wpr_header_v2_dump(struct nvkm_subdev *, const struct wpr_header_v2 *);
struct lsf_signature {
u8 prd_keys[2][16];
u8 dbg_keys[2][16];
@ -89,6 +106,74 @@ struct lsb_header_v1 {
void lsb_header_v1_dump(struct nvkm_subdev *, struct lsb_header_v1 *);
struct lsb_header_v2 {
struct wpr_generic_header hdr;
struct lsf_signature_v2 {
struct wpr_generic_header hdr;
u32 falcon_id;
u8 prd_present;
u8 dbg_present;
u16 reserved;
u32 sig_size;
u8 prod_sig[2][384 + 128];
u8 debug_sig[2][384 + 128];
u16 sig_algo_ver;
u16 sig_algo;
u16 hash_algo_ver;
u16 hash_algo;
u32 sig_algo_padding_type;
u8 depmap[11 * 2 * 4];
u32 depmap_count;
u8 supports_versioning;
u8 pad[3];
u32 ls_ucode_version;
u32 ls_ucode_id;
u32 ucode_ls_encrypted;
u32 ls_eng_algo_type;
u32 ls_eng_algo_ver;
u8 ls_enc_iv[16];
u8 rsvd[36];
} signature;
u32 ucode_off;
u32 ucode_size;
u32 data_size;
u32 bl_code_size;
u32 bl_imem_off;
u32 bl_data_off;
u32 bl_data_size;
u32 rsvd0;
u32 app_code_off;
u32 app_code_size;
u32 app_data_off;
u32 app_data_size;
u32 app_imem_offset;
u32 app_dmem_offset;
u32 flags;
u32 monitor_code_offset;
u32 monitor_data_offset;
u32 manifest_offset;
struct hs_fmc_params {
u8 hs_fmc;
u8 padding[3];
u16 pkc_algo;
u16 pkc_algo_version;
u32 engid_mask;
u32 ucode_id;
u32 fuse_ver;
u8 pkc_signature[384 + 128];
u8 pkc_key[2048];
u8 rsvd[4];
} hs_fmc_params;
struct hs_ovl_sig_blob_params {
u8 hs_ovl_sig_blob_present;
u32 hs_ovl_sig_blob_offset;
u32 hs_ovl_sig_blob_size;
} hs_ovl_sig_blob_params;
u8 rsvd[20];
};
void lsb_header_v2_dump(struct nvkm_subdev *, struct lsb_header_v2 *);
struct flcn_acr_desc {
union {
u8 reserved_dmem[0x200];

View file

@ -17,6 +17,20 @@ struct nvfw_hs_header {
const struct nvfw_hs_header *nvfw_hs_header(struct nvkm_subdev *, const void *);
struct nvfw_hs_header_v2 {
u32 sig_prod_offset;
u32 sig_prod_size;
u32 patch_loc;
u32 patch_sig;
u32 meta_data_offset;
u32 meta_data_size;
u32 num_sig;
u32 header_offset;
u32 header_size;
};
const struct nvfw_hs_header_v2 *nvfw_hs_header_v2(struct nvkm_subdev *, const void *);
struct nvfw_hs_load_header {
u32 non_sec_code_off;
u32 non_sec_code_size;
@ -28,4 +42,18 @@ struct nvfw_hs_load_header {
const struct nvfw_hs_load_header *
nvfw_hs_load_header(struct nvkm_subdev *, const void *);
struct nvfw_hs_load_header_v2 {
u32 os_code_offset;
u32 os_code_size;
u32 os_data_offset;
u32 os_data_size;
u32 num_apps;
struct {
u32 offset;
u32 size;
} app[0];
};
const struct nvfw_hs_load_header_v2 *nvfw_hs_load_header_v2(struct nvkm_subdev *, const void *);
#endif

View file

@ -50,4 +50,55 @@ struct nvfw_ls_desc_v1 {
const struct nvfw_ls_desc_v1 *
nvfw_ls_desc_v1(struct nvkm_subdev *, const void *);
struct nvfw_ls_desc_v2 {
u32 descriptor_size;
u32 image_size;
u32 tools_version;
u32 app_version;
char date[64];
u32 secure_bootloader;
u32 bootloader_start_offset;
u32 bootloader_size;
u32 bootloader_imem_offset;
u32 bootloader_entry_point;
u32 app_start_offset;
u32 app_size;
u32 app_imem_offset;
u32 app_imem_entry;
u32 app_dmem_offset;
u32 app_resident_code_offset;
u32 app_resident_code_size;
u32 app_resident_data_offset;
u32 app_resident_data_size;
u32 nb_imem_overlays;
u32 nb_dmem_overlays;
struct {
u32 start;
u32 size;
} load_ovl[64];
};
const struct nvfw_ls_desc_v2 *nvfw_ls_desc_v2(struct nvkm_subdev *, const void *);
struct nvfw_ls_hsbl_bin_hdr {
u32 bin_magic;
u32 bin_ver;
u32 bin_size;
u32 header_offset;
};
const struct nvfw_ls_hsbl_bin_hdr *nvfw_ls_hsbl_bin_hdr(struct nvkm_subdev *, const void *);
struct nvfw_ls_hsbl_hdr {
u32 sig_prod_offset;
u32 sig_prod_size;
u32 patch_loc;
u32 patch_sig;
u32 meta_data_offset;
u32 meta_data_size;
u32 num_sig;
};
const struct nvfw_ls_hsbl_hdr *nvfw_ls_hsbl_hdr(struct nvkm_subdev *, const void *);
#endif

View file

@ -10,6 +10,7 @@ struct nv_sec2_args {
};
#define NV_SEC2_UNIT_INIT 0x01
#define NV_SEC2_UNIT_UNLOAD 0x06
#define NV_SEC2_UNIT_ACR 0x08
struct nv_sec2_init_msg {
@ -33,6 +34,29 @@ struct nv_sec2_init_msg {
u16 sw_managed_area_size;
};
struct nv_sec2_init_msg_v1 {
struct nvfw_falcon_msg hdr;
#define NV_SEC2_INIT_MSG_INIT 0x00
u8 msg_type;
u8 num_queues;
u16 os_debug_entry_point;
struct {
u32 offset;
u16 size;
u8 index;
#define NV_SEC2_INIT_MSG_QUEUE_ID_CMDQ 0x00
#define NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ 0x01
u8 id;
} queue_info[2];
u32 sw_managed_area_offset;
u16 sw_managed_area_size;
u32 unkn[8];
};
struct nv_sec2_acr_cmd {
struct nvfw_falcon_cmd hdr;
#define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON 0x00
@ -57,4 +81,25 @@ struct nv_sec2_acr_bootstrap_falcon_msg {
u32 error_code;
u32 falcon_id;
};
#define NV_SEC2_UNIT_V2_INIT 0x01
#define NV_SEC2_UNIT_V2_UNLOAD 0x05
#define NV_SEC2_UNIT_V2_ACR 0x07
struct nv_sec2_acr_bootstrap_falcon_cmd_v1 {
struct nv_sec2_acr_cmd cmd;
#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0x00000000
#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_NO 0x00000001
u32 flags;
u32 falcon_id;
u32 unkn08;
u32 unkn0c;
};
struct nv_sec2_acr_bootstrap_falcon_msg_v1 {
struct nv_sec2_acr_msg msg;
u32 error_code;
u32 falcon_id;
u32 unkn08;
};
#endif

View file

@ -2,28 +2,5 @@
#ifndef __NVIF_CL0046_H__
#define __NVIF_CL0046_H__
#define NV04_DISP_NTFY_VBLANK 0x00
#define NV04_DISP_NTFY_CONN 0x01
struct nv04_disp_mthd_v0 {
__u8 version;
#define NV04_DISP_SCANOUTPOS 0x00
__u8 method;
__u8 head;
__u8 pad03[5];
};
struct nv04_disp_scanoutpos_v0 {
__u8 version;
__u8 pad01[7];
__s64 time[2];
__u16 vblanks;
__u16 vblanke;
__u16 vtotal;
__u16 vline;
__u16 hblanks;
__u16 hblanke;
__u16 htotal;
__u16 hline;
};
#endif

View file

@ -1,12 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL006B_H__
#define __NVIF_CL006B_H__
struct nv03_channel_dma_v0 {
__u8 version;
__u8 chid;
__u8 pad02[2];
__u32 offset;
__u64 pushbuf;
};
#endif

View file

@ -68,7 +68,7 @@ struct nv_device_time_v0 {
/* Returns the number of available runlists. */
#define NV_DEVICE_HOST_RUNLISTS NV_DEVICE_HOST(0x00000000)
/* Returns the number of available channels. */
/* Returns the number of available channels (0 if per-runlist). */
#define NV_DEVICE_HOST_CHANNELS NV_DEVICE_HOST(0x00000001)
/* Returns a mask of available engine types on runlist(data). */
@ -90,4 +90,6 @@ struct nv_device_time_v0 {
#define NV_DEVICE_HOST_RUNLIST_ENGINES_SEC2 0x00004000
#define NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC 0x00008000
#define NV_DEVICE_HOST_RUNLIST_ENGINES_NVENC 0x00010000
/* Returns the number of available channels on runlist(data). */
#define NV_DEVICE_HOST_RUNLIST_CHANNELS NV_DEVICE_HOST(0x00000101)
#endif

View file

@ -1,13 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL506E_H__
#define __NVIF_CL506E_H__
struct nv50_channel_dma_v0 {
__u8 version;
__u8 chid;
__u8 pad02[6];
__u64 vmm;
__u64 pushbuf;
__u64 offset;
};
#endif

View file

@ -1,14 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL506F_H__
#define __NVIF_CL506F_H__
struct nv50_channel_gpfifo_v0 {
__u8 version;
__u8 chid;
__u8 pad02[2];
__u32 ilength;
__u64 ioffset;
__u64 pushbuf;
__u64 vmm;
};
#endif

View file

@ -1,92 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL5070_H__
#define __NVIF_CL5070_H__
#define NV50_DISP_MTHD 0x00
struct nv50_disp_mthd_v0 {
__u8 version;
#define NV50_DISP_SCANOUTPOS 0x00
__u8 method;
__u8 head;
__u8 pad03[5];
};
struct nv50_disp_scanoutpos_v0 {
__u8 version;
__u8 pad01[7];
__s64 time[2];
__u16 vblanks;
__u16 vblanke;
__u16 vtotal;
__u16 vline;
__u16 hblanks;
__u16 hblanke;
__u16 htotal;
__u16 hline;
};
struct nv50_disp_mthd_v1 {
__u8 version;
#define NV50_DISP_MTHD_V1_ACQUIRE 0x01
#define NV50_DISP_MTHD_V1_RELEASE 0x02
#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22
#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
#define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25
#define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26
__u8 method;
__u16 hasht;
__u16 hashm;
__u8 pad06[2];
};
struct nv50_disp_acquire_v0 {
__u8 version;
__u8 or;
__u8 link;
__u8 hda;
__u8 pad04[4];
};
struct nv50_disp_sor_hda_eld_v0 {
__u8 version;
__u8 pad01[7];
__u8 data[];
};
struct nv50_disp_sor_hdmi_pwr_v0 {
__u8 version;
__u8 state;
__u8 max_ac_packet;
__u8 rekey;
__u8 avi_infoframe_length;
__u8 vendor_infoframe_length;
#define NV50_DISP_SOR_HDMI_PWR_V0_SCDC_SCRAMBLE (1 << 0)
#define NV50_DISP_SOR_HDMI_PWR_V0_SCDC_DIV_BY_4 (1 << 1)
__u8 scdc;
__u8 pad07[1];
};
struct nv50_disp_sor_lvds_script_v0 {
__u8 version;
__u8 pad01[1];
__u16 script;
__u8 pad04[4];
};
struct nv50_disp_sor_dp_mst_link_v0 {
__u8 version;
__u8 state;
__u8 pad02[6];
};
struct nv50_disp_sor_dp_mst_vcpi_v0 {
__u8 version;
__u8 pad01[1];
__u8 start_slot;
__u8 num_slots;
__u16 pbn;
__u16 aligned_pbn;
};
#endif

View file

@ -1,15 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL826E_H__
#define __NVIF_CL826E_H__
struct g82_channel_dma_v0 {
__u8 version;
__u8 chid;
__u8 pad02[6];
__u64 vmm;
__u64 pushbuf;
__u64 offset;
};
#define NV826E_V0_NTFY_NON_STALL_INTERRUPT 0x00
#endif

View file

@ -1,16 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL826F_H__
#define __NVIF_CL826F_H__
struct g82_channel_gpfifo_v0 {
__u8 version;
__u8 chid;
__u8 pad02[2];
__u32 ilength;
__u64 ioffset;
__u64 pushbuf;
__u64 vmm;
};
#define NV826F_V0_NTFY_NON_STALL_INTERRUPT 0x00
#endif

View file

@ -1,16 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL906F_H__
#define __NVIF_CL906F_H__
struct fermi_channel_gpfifo_v0 {
__u8 version;
__u8 chid;
__u8 pad02[2];
__u32 ilength;
__u64 ioffset;
__u64 vmm;
};
#define NV906F_V0_NTFY_NON_STALL_INTERRUPT 0x00
#define NV906F_V0_NTFY_KILLED 0x01
#endif

View file

@ -1,18 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CLA06F_H__
#define __NVIF_CLA06F_H__
struct kepler_channel_gpfifo_a_v0 {
__u8 version;
__u8 priv;
__u16 chid;
__u32 ilength;
__u64 ioffset;
__u64 runlist;
__u64 vmm;
__u64 inst;
};
#define NVA06F_V0_NTFY_NON_STALL_INTERRUPT 0x00
#define NVA06F_V0_NTFY_KILLED 0x01
#endif

View file

@ -32,11 +32,17 @@
#define NVIF_CLASS_VMM_GM200 /* ifb00d.h */ 0x8000b00d
#define NVIF_CLASS_VMM_GP100 /* ifc00d.h */ 0x8000c00d
#define NVIF_CLASS_EVENT /* if000e.h */ 0x8000000e
#define NVIF_CLASS_DISP /* if0010.h */ 0x80000010
#define NVIF_CLASS_CONN /* if0011.h */ 0x80000011
#define NVIF_CLASS_OUTP /* if0012.h */ 0x80000012
#define NVIF_CLASS_HEAD /* if0013.h */ 0x80000013
#define NVIF_CLASS_DISP_CHAN /* if0014.h */ 0x80000014
#define NVIF_CLASS_CHAN /* if0020.h */ 0x80000020
#define NVIF_CLASS_CGRP /* if0021.h */ 0x80000021
/* the below match nvidia-assigned (either in hw, or sw) class numbers */
#define NV_NULL_CLASS 0x00000030
@ -58,25 +64,30 @@
#define NV04_DISP /* cl0046.h */ 0x00000046
#define VOLTA_USERMODE_A 0x0000c361
#define TURING_USERMODE_A 0x0000c461
#define AMPERE_USERMODE_A 0x0000c561
#define MAXWELL_FAULT_BUFFER_A /* clb069.h */ 0x0000b069
#define VOLTA_FAULT_BUFFER_A /* clb069.h */ 0x0000c369
#define NV03_CHANNEL_DMA /* cl506b.h */ 0x0000006b
#define NV10_CHANNEL_DMA /* cl506b.h */ 0x0000006e
#define NV17_CHANNEL_DMA /* cl506b.h */ 0x0000176e
#define NV40_CHANNEL_DMA /* cl506b.h */ 0x0000406e
#define NV03_CHANNEL_DMA /* if0020.h */ 0x0000006b
#define NV10_CHANNEL_DMA /* if0020.h */ 0x0000006e
#define NV17_CHANNEL_DMA /* if0020.h */ 0x0000176e
#define NV40_CHANNEL_DMA /* if0020.h */ 0x0000406e
#define NV50_CHANNEL_GPFIFO /* cl506f.h */ 0x0000506f
#define G82_CHANNEL_GPFIFO /* cl826f.h */ 0x0000826f
#define FERMI_CHANNEL_GPFIFO /* cl906f.h */ 0x0000906f
#define KEPLER_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000a06f
#define KEPLER_CHANNEL_GPFIFO_B /* cla06f.h */ 0x0000a16f
#define MAXWELL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000b06f
#define PASCAL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000c06f
#define VOLTA_CHANNEL_GPFIFO_A /* clc36f.h */ 0x0000c36f
#define TURING_CHANNEL_GPFIFO_A /* clc36f.h */ 0x0000c46f
#define AMPERE_CHANNEL_GPFIFO_B /* clc36f.h */ 0x0000c76f
#define KEPLER_CHANNEL_GROUP_A /* if0021.h */ 0x0000a06c
#define NV50_CHANNEL_GPFIFO /* if0020.h */ 0x0000506f
#define G82_CHANNEL_GPFIFO /* if0020.h */ 0x0000826f
#define FERMI_CHANNEL_GPFIFO /* if0020.h */ 0x0000906f
#define KEPLER_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000a06f
#define KEPLER_CHANNEL_GPFIFO_B /* if0020.h */ 0x0000a16f
#define MAXWELL_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000b06f
#define PASCAL_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c06f
#define VOLTA_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c36f
#define TURING_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c46f
#define AMPERE_CHANNEL_GPFIFO_A /* if0020.h */ 0x0000c56f
#define AMPERE_CHANNEL_GPFIFO_B /* if0020.h */ 0x0000c76f
#define NV50_DISP /* if0010.h */ 0x00005070
#define G82_DISP /* if0010.h */ 0x00008270
@ -179,6 +190,8 @@
#define TURING_A /* cl9097.h */ 0x0000c597
#define AMPERE_B /* cl9097.h */ 0x0000c797
#define NV74_BSP 0x000074b0
#define GT212_MSVLD 0x000085b1
@ -206,6 +219,7 @@
#define PASCAL_DMA_COPY_B 0x0000c1b5
#define VOLTA_DMA_COPY_A 0x0000c3b5
#define TURING_DMA_COPY_A 0x0000c5b5
#define AMPERE_DMA_COPY_A 0x0000c6b5
#define AMPERE_DMA_COPY_B 0x0000c7b5
#define FERMI_DECOMPRESS 0x000090b8
@ -222,6 +236,7 @@
#define PASCAL_COMPUTE_B 0x0000c1c0
#define VOLTA_COMPUTE_A 0x0000c3c0
#define TURING_COMPUTE_A 0x0000c5c0
#define AMPERE_COMPUTE_B 0x0000c7c0
#define NV74_CIPHER 0x000074c1
#endif

View file

@ -8,5 +8,8 @@ struct nvif_clb069_v0 {
__u32 put;
};
#define NVB069_V0_NTFY_FAULT 0x00
union nvif_clb069_event_args {
struct nvif_clb069_event_vn {
} vn;
};
#endif

View file

@ -1,19 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CLC36F_H__
#define __NVIF_CLC36F_H__
struct volta_channel_gpfifo_a_v0 {
__u8 version;
__u8 priv;
__u16 chid;
__u32 ilength;
__u64 ioffset;
__u64 runlist;
__u64 vmm;
__u64 inst;
__u32 token;
};
#define NVC36F_V0_NTFY_NON_STALL_INTERRUPT 0x00
#define NVC36F_V0_NTFY_KILLED 0x01
#endif

View file

@ -2,6 +2,7 @@
#ifndef __NVIF_CONN_H__
#define __NVIF_CONN_H__
#include <nvif/object.h>
#include <nvif/event.h>
struct nvif_disp;
struct nvif_conn {
@ -11,8 +12,17 @@ struct nvif_conn {
int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *);
void nvif_conn_dtor(struct nvif_conn *);
static inline int
nvif_conn_id(struct nvif_conn *conn)
{
return conn->object.handle;
}
#define NVIF_CONN_HPD_STATUS_UNSUPPORTED 0 /* negative if query fails */
#define NVIF_CONN_HPD_STATUS_NOT_PRESENT 1
#define NVIF_CONN_HPD_STATUS_PRESENT 2
int nvif_conn_hpd_status(struct nvif_conn *);
int nvif_conn_event_ctor(struct nvif_conn *, const char *name, nvif_event_func, u8 types,
struct nvif_event *);
#endif

View file

@ -7,6 +7,7 @@ struct nvif_disp {
struct nvif_object object;
unsigned long conn_mask;
unsigned long outp_mask;
unsigned long head_mask;
};
int nvif_disp_ctor(struct nvif_device *, const char *name, s32 oclass,

View file

@ -1,63 +1,36 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_EVENT_H__
#define __NVIF_EVENT_H__
#include <nvif/object.h>
#include <nvif/if000e.h>
struct nvif_event;
struct nvif_notify_req_v0 {
__u8 version;
__u8 reply;
__u8 pad02[5];
#define NVIF_NOTIFY_V0_ROUTE_NVIF 0x00
__u8 route;
__u64 token; /* must be unique */
__u8 data[]; /* request data (below) */
#define NVIF_EVENT_KEEP 0
#define NVIF_EVENT_DROP 1
typedef int (*nvif_event_func)(struct nvif_event *, void *repv, u32 repc);
struct nvif_event {
struct nvif_object object;
nvif_event_func func;
};
struct nvif_notify_rep_v0 {
__u8 version;
__u8 pad01[6];
__u8 route;
__u64 token;
__u8 data[]; /* reply data (below) */
};
static inline bool
nvif_event_constructed(struct nvif_event *event)
{
return nvif_object_constructed(&event->object);
}
struct nvif_notify_head_req_v0 {
/* nvif_notify_req ... */
__u8 version;
__u8 head;
__u8 pad02[6];
};
int nvif_event_ctor_(struct nvif_object *, const char *, u32, nvif_event_func, bool,
struct nvif_event_v0 *, u32, bool, struct nvif_event *);
struct nvif_notify_head_rep_v0 {
/* nvif_notify_rep ... */
__u8 version;
__u8 pad01[7];
};
struct nvif_notify_conn_req_v0 {
/* nvif_notify_req ... */
__u8 version;
#define NVIF_NOTIFY_CONN_V0_PLUG 0x01
#define NVIF_NOTIFY_CONN_V0_UNPLUG 0x02
#define NVIF_NOTIFY_CONN_V0_IRQ 0x04
#define NVIF_NOTIFY_CONN_V0_ANY 0x07
__u8 mask;
__u8 conn;
__u8 pad03[5];
};
struct nvif_notify_conn_rep_v0 {
/* nvif_notify_rep ... */
__u8 version;
__u8 mask;
__u8 pad02[6];
};
struct nvif_notify_uevent_req {
/* nvif_notify_req ... */
};
struct nvif_notify_uevent_rep {
/* nvif_notify_rep ... */
};
static inline int
nvif_event_ctor(struct nvif_object *parent, const char *name, u32 handle, nvif_event_func func,
bool wait, struct nvif_event_v0 *args, u32 argc, struct nvif_event *event)
{
return nvif_event_ctor_(parent, name, handle, func, wait, args, argc, true, event);
}
void nvif_event_dtor(struct nvif_event *);
int nvif_event_allow(struct nvif_event *);
int nvif_event_block(struct nvif_event *);
#endif

View file

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_HEAD_H__
#define __NVIF_HEAD_H__
#include <nvif/object.h>
#include <nvif/event.h>
struct nvif_disp;
struct nvif_head {
struct nvif_object object;
};
int nvif_head_ctor(struct nvif_disp *, const char *name, int id, struct nvif_head *);
void nvif_head_dtor(struct nvif_head *);
static inline int
nvif_head_id(struct nvif_head *head)
{
return head->object.handle;
}
int nvif_head_vblank_event_ctor(struct nvif_head *, const char *name, nvif_event_func, bool wait,
struct nvif_event *);
#endif

View file

@ -2,7 +2,10 @@
#ifndef __NVIF_IF0004_H__
#define __NVIF_IF0004_H__
#define NV04_NVSW_NTFY_UEVENT 0x00
union nv04_nvsw_event_args {
struct nv04_nvsw_event_vn {
} vn;
};
#define NV04_NVSW_GET_REF 0x00

View file

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF000E_H__
#define __NVIF_IF000E_H__
union nvif_event_args {
struct nvif_event_v0 {
__u8 version;
__u8 wait;
__u8 pad02[6];
__u8 data[];
} v0;
};
#define NVIF_EVENT_V0_ALLOW 0x00
#define NVIF_EVENT_V0_BLOCK 0x01
union nvif_event_allow_args {
struct nvif_event_allow_vn {
} vn;
};
union nvif_event_block_args {
struct nvif_event_block_vn {
} vn;
};
#endif

View file

@ -8,6 +8,7 @@ union nvif_disp_args {
__u8 pad01[3];
__u32 conn_mask;
__u32 outp_mask;
__u32 head_mask;
} v0;
};
#endif

View file

@ -10,6 +10,17 @@ union nvif_conn_args {
} v0;
};
union nvif_conn_event_args {
struct nvif_conn_event_v0 {
__u8 version;
#define NVIF_CONN_EVENT_V0_PLUG 0x01
#define NVIF_CONN_EVENT_V0_UNPLUG 0x02
#define NVIF_CONN_EVENT_V0_IRQ 0x04
__u8 types;
__u8 pad02[6];
} v0;
};
#define NVIF_CONN_V0_HPD_STATUS 0x00000000
union nvif_conn_hpd_status_args {

View file

@ -11,6 +11,13 @@ union nvif_outp_args {
};
#define NVIF_OUTP_V0_LOAD_DETECT 0x00
#define NVIF_OUTP_V0_ACQUIRE 0x01
#define NVIF_OUTP_V0_RELEASE 0x02
#define NVIF_OUTP_V0_INFOFRAME 0x03
#define NVIF_OUTP_V0_HDA_ELD 0x04
#define NVIF_OUTP_V0_DP_AUX_PWR 0x05
#define NVIF_OUTP_V0_DP_RETRAIN 0x06
#define NVIF_OUTP_V0_DP_MST_VCPI 0x07
union nvif_outp_load_detect_args {
struct nvif_outp_load_detect_v0 {
@ -20,4 +27,95 @@ union nvif_outp_load_detect_args {
__u32 data; /*TODO: move vbios loadval parsing into nvkm */
} v0;
};
union nvif_outp_acquire_args {
struct nvif_outp_acquire_v0 {
__u8 version;
#define NVIF_OUTP_ACQUIRE_V0_RGB_CRT 0x00
#define NVIF_OUTP_ACQUIRE_V0_TV 0x01
#define NVIF_OUTP_ACQUIRE_V0_TMDS 0x02
#define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03
#define NVIF_OUTP_ACQUIRE_V0_DP 0x04
__u8 proto;
__u8 or;
__u8 link;
__u8 pad04[4];
union {
struct {
__u8 head;
__u8 hdmi;
__u8 hdmi_max_ac_packet;
__u8 hdmi_rekey;
#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_SCRAMBLE (1 << 0)
#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_DIV_BY_4 (1 << 1)
__u8 hdmi_scdc;
__u8 hdmi_hda;
__u8 pad06[2];
} tmds;
struct {
__u8 dual;
__u8 bpc8;
__u8 pad02[6];
} lvds;
struct {
__u8 link_nr; /* 0 = highest possible. */
__u8 link_bw; /* 0 = highest possible, DP BW code otherwise. */
__u8 hda;
__u8 mst;
__u8 pad04[4];
__u8 dpcd[16];
} dp;
};
} v0;
};
union nvif_outp_release_args {
struct nvif_outp_release_vn {
} vn;
};
union nvif_outp_infoframe_args {
struct nvif_outp_infoframe_v0 {
__u8 version;
#define NVIF_OUTP_INFOFRAME_V0_AVI 0
#define NVIF_OUTP_INFOFRAME_V0_VSI 1
__u8 type;
__u8 head;
__u8 pad03[5];
__u8 data[];
} v0;
};
union nvif_outp_hda_eld_args {
struct nvif_outp_hda_eld_v0 {
__u8 version;
__u8 head;
__u8 pad02[6];
__u8 data[];
} v0;
};
union nvif_outp_dp_aux_pwr_args {
struct nvif_outp_dp_aux_pwr_v0 {
__u8 version;
__u8 state;
__u8 pad02[6];
} v0;
};
union nvif_outp_dp_retrain_args {
struct nvif_outp_dp_retrain_vn {
} vn;
};
union nvif_outp_dp_mst_vcpi_args {
struct nvif_outp_dp_mst_vcpi_v0 {
__u8 version;
__u8 head;
__u8 start_slot;
__u8 num_slots;
__u16 pbn;
__u16 aligned_pbn;
} v0;
};
#endif

View file

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF0013_H__
#define __NVIF_IF0013_H__
union nvif_head_args {
struct nvif_head_v0 {
__u8 version;
__u8 id;
__u8 pad02[6];
} v0;
};
union nvif_head_event_args {
struct nvif_head_event_vn {
} vn;
};
#define NVIF_HEAD_V0_SCANOUTPOS 0x00
union nvif_head_scanoutpos_args {
struct nvif_head_scanoutpos_v0 {
__u8 version;
__u8 pad01[7];
__s64 time[2];
__u16 vblanks;
__u16 vblanke;
__u16 vtotal;
__u16 vline;
__u16 hblanks;
__u16 hblanke;
__u16 htotal;
__u16 hline;
} v0;
};
#endif

View file

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF0020_H__
#define __NVIF_IF0020_H__
union nvif_chan_args {
struct nvif_chan_v0 {
__u8 version;
__u8 namelen;
__u8 runlist;
__u8 runq;
__u8 priv;
__u8 pad05;
__u16 devm;
__u64 vmm;
__u64 ctxdma;
__u64 offset;
__u64 length;
__u64 huserd;
__u64 ouserd;
__u32 token;
__u16 chid;
__u8 pad3e;
#define NVIF_CHAN_V0_INST_APER_VRAM 0
#define NVIF_CHAN_V0_INST_APER_HOST 1
#define NVIF_CHAN_V0_INST_APER_NCOH 2
#define NVIF_CHAN_V0_INST_APER_INST 0xff
__u8 aper;
__u64 inst;
__u8 name[];
} v0;
};
union nvif_chan_event_args {
struct nvif_chan_event_v0 {
__u8 version;
#define NVIF_CHAN_EVENT_V0_NON_STALL_INTR 0x00
#define NVIF_CHAN_EVENT_V0_KILLED 0x01
__u8 type;
} v0;
};
#endif

View file

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF0021_H__
#define __NVIF_IF0021_H__
union nvif_cgrp_args {
struct nvif_cgrp_v0 {
__u8 version;
__u8 namelen;
__u8 runlist;
__u8 pad03[3];
__u16 cgid;
__u64 vmm;
__u8 name[];
} v0;
};
#endif

View file

@ -15,10 +15,6 @@ struct nvif_ioctl_v0 {
#define NVIF_IOCTL_V0_WR 0x06
#define NVIF_IOCTL_V0_MAP 0x07
#define NVIF_IOCTL_V0_UNMAP 0x08
#define NVIF_IOCTL_V0_NTFY_NEW 0x09
#define NVIF_IOCTL_V0_NTFY_DEL 0x0a
#define NVIF_IOCTL_V0_NTFY_GET 0x0b
#define NVIF_IOCTL_V0_NTFY_PUT 0x0c
__u8 type;
__u8 pad02[4];
#define NVIF_IOCTL_V0_OWNER_NVIF 0x00
@ -63,6 +59,14 @@ struct nvif_ioctl_new_v0 {
struct nvif_ioctl_del {
};
struct nvif_ioctl_mthd_v0 {
/* nvif_ioctl ... */
__u8 version;
__u8 method;
__u8 pad02[6];
__u8 data[]; /* method data (class.h) */
};
struct nvif_ioctl_rd_v0 {
/* nvif_ioctl ... */
__u8 version;
@ -95,43 +99,4 @@ struct nvif_ioctl_map_v0 {
struct nvif_ioctl_unmap {
};
struct nvif_ioctl_ntfy_new_v0 {
/* nvif_ioctl ... */
__u8 version;
__u8 event;
__u8 index;
__u8 pad03[5];
__u8 data[]; /* event request data (event.h) */
};
struct nvif_ioctl_ntfy_del_v0 {
/* nvif_ioctl ... */
__u8 version;
__u8 index;
__u8 pad02[6];
};
struct nvif_ioctl_ntfy_get_v0 {
/* nvif_ioctl ... */
__u8 version;
__u8 index;
__u8 pad02[6];
};
struct nvif_ioctl_ntfy_put_v0 {
/* nvif_ioctl ... */
__u8 version;
__u8 index;
__u8 pad02[6];
};
struct nvif_ioctl_mthd_v0 {
/* nvif_ioctl ... */
__u8 version;
__u8 method;
__u8 pad02[6];
__u8 data[]; /* method data (class.h) */
};
#endif

View file

@ -1,35 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_NOTIFY_H__
#define __NVIF_NOTIFY_H__
struct nvif_notify {
struct nvif_object *object;
const char *name;
int index;
#define NVIF_NOTIFY_USER 0
#define NVIF_NOTIFY_WORK 1
unsigned long flags;
atomic_t putcnt;
void (*dtor)(struct nvif_notify *);
#define NVIF_NOTIFY_DROP 0
#define NVIF_NOTIFY_KEEP 1
int (*func)(struct nvif_notify *);
/* this is const for a *very* good reason - the data might be on the
* stack from an irq handler. if you're not nvif/notify.c then you
* should probably think twice before casting it away...
*/
const void *data;
u32 size;
struct work_struct work;
};
int nvif_notify_ctor(struct nvif_object *, const char *name,
int (*func)(struct nvif_notify *), bool work, u8 type,
void *data, u32 size, u32 reply, struct nvif_notify *);
int nvif_notify_dtor(struct nvif_notify *);
int nvif_notify_get(struct nvif_notify *);
int nvif_notify_put(struct nvif_notify *);
int nvif_notify(const void *, u32, const void *, u32);
#endif

View file

@ -2,13 +2,32 @@
#ifndef __NVIF_OUTP_H__
#define __NVIF_OUTP_H__
#include <nvif/object.h>
#include <nvif/if0012.h>
struct nvif_disp;
struct nvif_outp {
struct nvif_object object;
struct {
int id;
int link;
} or;
};
int nvif_outp_ctor(struct nvif_disp *, const char *name, int id, struct nvif_outp *);
void nvif_outp_dtor(struct nvif_outp *);
int nvif_outp_load_detect(struct nvif_outp *, u32 loadval);
int nvif_outp_acquire_rgb_crt(struct nvif_outp *);
int nvif_outp_acquire_tmds(struct nvif_outp *, int head,
bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda);
int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8);
int nvif_outp_acquire_dp(struct nvif_outp *, u8 dpcd[16],
int link_nr, int link_bw, bool hda, bool mst);
void nvif_outp_release(struct nvif_outp *);
int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size);
int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size);
int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable);
int nvif_outp_dp_retrain(struct nvif_outp *);
int nvif_outp_dp_mst_vcpi(struct nvif_outp *, int head,
u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn);
#endif

View file

@ -10,28 +10,19 @@ struct nvkm_client {
u64 device;
u32 debug;
struct nvkm_client_notify *notify[32];
struct rb_root objroot;
void *data;
int (*ntfy)(const void *, u32, const void *, u32);
int (*event)(u64 token, void *argv, u32 argc);
struct list_head umem;
spinlock_t lock;
};
int nvkm_client_new(const char *name, u64 device, const char *cfg,
const char *dbg,
int (*)(const void *, u32, const void *, u32),
struct nvkm_client **);
int nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg,
int (*)(u64, void *, u32), struct nvkm_client **);
struct nvkm_client *nvkm_client_search(struct nvkm_client *, u64 handle);
int nvkm_client_notify_new(struct nvkm_object *, struct nvkm_event *,
void *data, u32 size);
int nvkm_client_notify_del(struct nvkm_client *, int index);
int nvkm_client_notify_get(struct nvkm_client *, int index);
int nvkm_client_notify_put(struct nvkm_client *, int index);
/* logging for client-facing objects */
#define nvif_printk(o,l,p,f,a...) do { \
const struct nvkm_object *_object = (o); \

View file

@ -2,6 +2,7 @@
#ifndef __NVKM_DEVICE_H__
#define __NVKM_DEVICE_H__
#include <core/oclass.h>
#include <core/intr.h>
enum nvkm_subdev_type;
enum nvkm_device_type {
@ -60,6 +61,16 @@ struct nvkm_device {
#undef NVKM_LAYOUT_INST
#undef NVKM_LAYOUT_ONCE
struct list_head subdev;
struct {
struct list_head intr;
struct list_head prio[NVKM_INTR_PRIO_NR];
spinlock_t lock;
int irq;
bool alloc;
bool armed;
bool legacy_done;
} intr;
};
struct nvkm_subdev *nvkm_device_subdev(struct nvkm_device *, int type, int inst);
@ -72,6 +83,7 @@ struct nvkm_device_func {
int (*preinit)(struct nvkm_device *);
int (*init)(struct nvkm_device *);
void (*fini)(struct nvkm_device *, bool suspend);
int (*irq)(struct nvkm_device *);
resource_size_t (*resource_addr)(struct nvkm_device *, unsigned bar);
resource_size_t (*resource_size)(struct nvkm_device *, unsigned bar);
bool cpu_coherent;

View file

@ -12,12 +12,6 @@ struct nvkm_engine {
const struct nvkm_engine_func *func;
struct nvkm_subdev subdev;
spinlock_t lock;
struct {
refcount_t refcount;
struct mutex mutex;
bool enabled;
} use;
};
struct nvkm_engine_func {
@ -27,6 +21,7 @@ struct nvkm_engine_func {
int (*info)(struct nvkm_engine *, u64 mthd, u64 *data);
int (*init)(struct nvkm_engine *);
int (*fini)(struct nvkm_engine *, bool suspend);
int (*reset)(struct nvkm_engine *);
void (*intr)(struct nvkm_engine *);
void (*tile)(struct nvkm_engine *, int region, struct nvkm_fb_tile *);
bool (*chsw_load)(struct nvkm_engine *);
@ -54,6 +49,7 @@ int nvkm_engine_new_(const struct nvkm_engine_func *, struct nvkm_device *,
struct nvkm_engine *nvkm_engine_ref(struct nvkm_engine *);
void nvkm_engine_unref(struct nvkm_engine **);
int nvkm_engine_reset(struct nvkm_engine *);
void nvkm_engine_tile(struct nvkm_engine *, int region);
bool nvkm_engine_chsw_load(struct nvkm_engine *);
#endif

View file

@ -2,34 +2,76 @@
#ifndef __NVKM_EVENT_H__
#define __NVKM_EVENT_H__
#include <core/os.h>
struct nvkm_notify;
struct nvkm_object;
struct nvkm_oclass;
struct nvkm_uevent;
struct nvkm_event {
const struct nvkm_event_func *func;
struct nvkm_subdev *subdev;
int types_nr;
int index_nr;
spinlock_t refs_lock;
spinlock_t list_lock;
struct list_head list;
int *refs;
struct list_head ntfy;
};
struct nvkm_event_func {
int (*ctor)(struct nvkm_object *, void *data, u32 size,
struct nvkm_notify *);
void (*send)(void *data, u32 size, struct nvkm_notify *);
void (*init)(struct nvkm_event *, int type, int index);
void (*fini)(struct nvkm_event *, int type, int index);
};
int nvkm_event_init(const struct nvkm_event_func *func, int types_nr,
int index_nr, struct nvkm_event *);
int __nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *, int types_nr,
int index_nr, struct nvkm_event *);
/* Each nvkm_event needs its own lockdep class due to inter-dependencies, to
* prevent lockdep false-positives.
*
* Inlining the spinlock initialisation ensures each is unique.
*/
static __always_inline int
nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *subdev,
int types_nr, int index_nr, struct nvkm_event *event)
{
spin_lock_init(&event->refs_lock);
spin_lock_init(&event->list_lock);
return __nvkm_event_init(func, subdev, types_nr, index_nr, event);
}
void nvkm_event_fini(struct nvkm_event *);
void nvkm_event_get(struct nvkm_event *, u32 types, int index);
void nvkm_event_put(struct nvkm_event *, u32 types, int index);
void nvkm_event_send(struct nvkm_event *, u32 types, int index,
void *data, u32 size);
#define NVKM_EVENT_KEEP 0
#define NVKM_EVENT_DROP 1
struct nvkm_event_ntfy;
typedef int (*nvkm_event_func)(struct nvkm_event_ntfy *, u32 bits);
struct nvkm_event_ntfy {
struct nvkm_event *event;
int id;
u32 bits;
bool wait;
nvkm_event_func func;
atomic_t allowed;
bool running;
struct list_head head;
};
void nvkm_event_ntfy(struct nvkm_event *, int id, u32 bits);
bool nvkm_event_ntfy_valid(struct nvkm_event *, int id, u32 bits);
void nvkm_event_ntfy_add(struct nvkm_event *, int id, u32 bits, bool wait, nvkm_event_func,
struct nvkm_event_ntfy *);
void nvkm_event_ntfy_del(struct nvkm_event_ntfy *);
void nvkm_event_ntfy_allow(struct nvkm_event_ntfy *);
void nvkm_event_ntfy_block(struct nvkm_event_ntfy *);
typedef int (*nvkm_uevent_func)(struct nvkm_object *, u64 token, u32 bits);
int nvkm_uevent_new(const struct nvkm_oclass *, void *argv, u32 argc, struct nvkm_object **);
int nvkm_uevent_add(struct nvkm_uevent *, struct nvkm_event *, int id, u32 bits, nvkm_uevent_func);
#endif

View file

@ -1,34 +1,166 @@
#ifndef __NVKM_FALCON_H__
#define __NVKM_FALCON_H__
#include <core/firmware.h>
#include <engine/falcon.h>
enum nvkm_falcon_mem {
IMEM,
DMEM,
EMEM,
};
static inline const char *
nvkm_falcon_mem(enum nvkm_falcon_mem mem)
{
switch (mem) {
case IMEM: return "imem";
case DMEM: return "dmem";
case EMEM: return "emem";
default:
WARN_ON(1);
return "?mem";
}
}
struct nvkm_falcon_func_pio {
int min;
int max;
void (*wr_init)(struct nvkm_falcon *, u8 port, bool sec, u32 mem_base);
void (*wr)(struct nvkm_falcon *, u8 port, const u8 *img, int len, u16 tag);
void (*rd_init)(struct nvkm_falcon *, u8 port, u32 mem_base);
void (*rd)(struct nvkm_falcon *, u8 port, const u8 *img, int len);
};
struct nvkm_falcon_func_dma {
int (*init)(struct nvkm_falcon *, u64 dma_addr, int xfer_len,
enum nvkm_falcon_mem, bool sec, u32 *cmd);
void (*xfer)(struct nvkm_falcon *, u32 mem_base, u32 dma_base, u32 cmd);
bool (*done)(struct nvkm_falcon *);
};
int nvkm_falcon_ctor(const struct nvkm_falcon_func *, struct nvkm_subdev *owner,
const char *name, u32 addr, struct nvkm_falcon *);
void nvkm_falcon_dtor(struct nvkm_falcon *);
int nvkm_falcon_reset(struct nvkm_falcon *);
int nvkm_falcon_pio_wr(struct nvkm_falcon *, const u8 *img, u32 img_base, u8 port,
enum nvkm_falcon_mem mem_type, u32 mem_base, int len, u16 tag, bool sec);
int nvkm_falcon_pio_rd(struct nvkm_falcon *, u8 port, enum nvkm_falcon_mem type, u32 mem_base,
const u8 *img, u32 img_base, int len);
int nvkm_falcon_dma_wr(struct nvkm_falcon *, const u8 *img, u64 dma_addr, u32 dma_base,
enum nvkm_falcon_mem mem_type, u32 mem_base, int len, bool sec);
int gm200_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *);
int gm200_flcn_disable(struct nvkm_falcon *);
int gm200_flcn_enable(struct nvkm_falcon *);
void gm200_flcn_bind_inst(struct nvkm_falcon *, int, u64);
int gm200_flcn_bind_stat(struct nvkm_falcon *, bool);
extern const struct nvkm_falcon_func_pio gm200_flcn_imem_pio;
extern const struct nvkm_falcon_func_pio gm200_flcn_dmem_pio;
void gm200_flcn_tracepc(struct nvkm_falcon *);
int gp102_flcn_reset_eng(struct nvkm_falcon *);
extern const struct nvkm_falcon_func_pio gp102_flcn_emem_pio;
int ga102_flcn_select(struct nvkm_falcon *);
int ga102_flcn_reset_prep(struct nvkm_falcon *);
int ga102_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *);
extern const struct nvkm_falcon_func_dma ga102_flcn_dma;
void nvkm_falcon_v1_load_imem(struct nvkm_falcon *,
void *, u32, u32, u16, u8, bool);
void nvkm_falcon_v1_load_dmem(struct nvkm_falcon *, void *, u32, u32, u8);
void nvkm_falcon_v1_read_dmem(struct nvkm_falcon *, u32, u32, u8, void *);
void nvkm_falcon_v1_bind_context(struct nvkm_falcon *, struct nvkm_memory *);
int nvkm_falcon_v1_wait_for_halt(struct nvkm_falcon *, u32);
int nvkm_falcon_v1_clear_interrupt(struct nvkm_falcon *, u32);
void nvkm_falcon_v1_set_start_addr(struct nvkm_falcon *, u32 start_addr);
void nvkm_falcon_v1_start(struct nvkm_falcon *);
int nvkm_falcon_v1_enable(struct nvkm_falcon *);
void nvkm_falcon_v1_disable(struct nvkm_falcon *);
void gp102_sec2_flcn_bind_context(struct nvkm_falcon *, struct nvkm_memory *);
int gp102_sec2_flcn_enable(struct nvkm_falcon *);
#define FLCN_PRINTK(f,l,p,fmt,a...) ({ \
if ((f)->owner->name != (f)->name) \
nvkm_printk___((f)->owner, (f)->user, NV_DBG_##l, p, "%s:"fmt, (f)->name, ##a); \
else \
nvkm_printk___((f)->owner, (f)->user, NV_DBG_##l, p, fmt, ##a); \
})
#define FLCN_DBG(f,fmt,a...) FLCN_PRINTK((f), DEBUG, info, " "fmt"\n", ##a)
#define FLCN_ERR(f,fmt,a...) FLCN_PRINTK((f), ERROR, err, " "fmt"\n", ##a)
#define FLCN_ERRON(f,c,fmt,a...) \
({ bool _cond = (c); _cond ? FLCN_ERR(f, fmt, ##a) : FLCN_DBG(f, fmt, ##a); _cond; })
#define FLCN_PRINTK(t,f,fmt,a...) do { \
if ((f)->owner->name != (f)->name) \
nvkm_##t((f)->owner, "%s: "fmt"\n", (f)->name, ##a); \
else \
nvkm_##t((f)->owner, fmt"\n", ##a); \
} while(0)
#define FLCN_DBG(f,fmt,a...) FLCN_PRINTK(debug, (f), fmt, ##a)
#define FLCN_ERR(f,fmt,a...) FLCN_PRINTK(error, (f), fmt, ##a)
struct nvkm_falcon_fw {
const struct nvkm_falcon_fw_func {
int (*signature)(struct nvkm_falcon_fw *, u32 *sig_base_src);
int (*reset)(struct nvkm_falcon_fw *);
int (*setup)(struct nvkm_falcon_fw *);
int (*load)(struct nvkm_falcon_fw *);
int (*load_bld)(struct nvkm_falcon_fw *);
int (*boot)(struct nvkm_falcon_fw *,
u32 *mbox0, u32 *mbox1, u32 mbox0_ok, u32 irqsclr);
} *func;
struct nvkm_firmware fw;
u32 sig_base_prd;
u32 sig_base_dbg;
u32 sig_base_img;
u32 sig_size;
int sig_nr;
u8 *sigs;
u32 fuse_ver;
u32 engine_id;
u32 ucode_id;
u32 nmem_base_img;
u32 nmem_base;
u32 nmem_size;
u32 imem_base_img;
u32 imem_base;
u32 imem_size;
u32 dmem_base_img;
u32 dmem_base;
u32 dmem_size;
u32 dmem_sign;
u8 *boot;
u32 boot_size;
u32 boot_addr;
struct nvkm_falcon *falcon;
struct nvkm_memory *inst;
struct nvkm_vmm *vmm;
struct nvkm_vma *vma;
};
int nvkm_falcon_fw_ctor(const struct nvkm_falcon_fw_func *, const char *name, struct nvkm_device *,
bool bl, const void *src, u32 len, struct nvkm_falcon *,
struct nvkm_falcon_fw *);
int nvkm_falcon_fw_ctor_hs(const struct nvkm_falcon_fw_func *, const char *name,
struct nvkm_subdev *, const char *bl, const char *img, int ver,
struct nvkm_falcon *falcon, struct nvkm_falcon_fw *fw);
int nvkm_falcon_fw_ctor_hs_v2(const struct nvkm_falcon_fw_func *, const char *name,
struct nvkm_subdev *, const char *img, int ver, struct nvkm_falcon *,
struct nvkm_falcon_fw *);
int nvkm_falcon_fw_sign(struct nvkm_falcon_fw *, u32 sig_base_img, u32 sig_size, const u8 *sigs,
int sig_nr_prd, u32 sig_base_prd, int sig_nr_dbg, u32 sig_base_dbg);
int nvkm_falcon_fw_patch(struct nvkm_falcon_fw *);
void nvkm_falcon_fw_dtor(struct nvkm_falcon_fw *);
int nvkm_falcon_fw_oneinit(struct nvkm_falcon_fw *, struct nvkm_falcon *, struct nvkm_vmm *,
struct nvkm_memory *inst);
int nvkm_falcon_fw_boot(struct nvkm_falcon_fw *, struct nvkm_subdev *user,
bool release, u32 *pmbox0, u32 *pmbox1, u32 mbox0_ok, u32 irqsclr);
extern const struct nvkm_falcon_fw_func gm200_flcn_fw;
int gm200_flcn_fw_signature(struct nvkm_falcon_fw *, u32 *);
int gm200_flcn_fw_reset(struct nvkm_falcon_fw *);
int gm200_flcn_fw_load(struct nvkm_falcon_fw *);
int gm200_flcn_fw_boot(struct nvkm_falcon_fw *, u32 *, u32 *, u32, u32);
int ga100_flcn_fw_signature(struct nvkm_falcon_fw *, u32 *);
extern const struct nvkm_falcon_fw_func ga102_flcn_fw;
int ga102_flcn_fw_load(struct nvkm_falcon_fw *);
int ga102_flcn_fw_boot(struct nvkm_falcon_fw *, u32 *, u32 *, u32, u32);
#define FLCNFW_PRINTK(f,l,p,fmt,a...) FLCN_PRINTK((f)->falcon, l, p, "%s: "fmt, (f)->fw.name, ##a)
#define FLCNFW_DBG(f,fmt,a...) FLCNFW_PRINTK((f), DEBUG, info, fmt"\n", ##a)
#define FLCNFW_ERR(f,fmt,a...) FLCNFW_PRINTK((f), ERROR, err, fmt"\n", ##a)
/**
* struct nvfw_falcon_msg - header for all messages
@ -72,6 +204,7 @@ int nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *, const char *name,
void nvkm_falcon_msgq_del(struct nvkm_falcon_msgq **);
void nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *,
u32 index, u32 offset, u32 size);
bool nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *);
int nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *, void *, u32 size);
void nvkm_falcon_msgq_recv(struct nvkm_falcon_msgq *);
#endif

View file

@ -1,9 +1,34 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_FIRMWARE_H__
#define __NVKM_FIRMWARE_H__
#include <core/memory.h>
#include <core/option.h>
#include <core/subdev.h>
struct nvkm_firmware {
const struct nvkm_firmware_func {
enum nvkm_firmware_type {
NVKM_FIRMWARE_IMG_RAM,
NVKM_FIRMWARE_IMG_DMA,
} type;
} *func;
const char *name;
struct nvkm_device *device;
int len;
u8 *img;
u64 phys;
struct nvkm_firmware_mem {
struct nvkm_memory memory;
struct scatterlist sgl;
} mem;
};
int nvkm_firmware_ctor(const struct nvkm_firmware_func *, const char *name, struct nvkm_device *,
const void *ptr, int len, struct nvkm_firmware *);
void nvkm_firmware_dtor(struct nvkm_firmware *);
int nvkm_firmware_get(const struct nvkm_subdev *, const char *fwname, int ver,
const struct firmware **);
void nvkm_firmware_put(const struct firmware *);

View file

@ -0,0 +1,73 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_INTR_H__
#define __NVKM_INTR_H__
#include <core/os.h>
struct nvkm_device;
struct nvkm_subdev;
enum nvkm_intr_prio {
NVKM_INTR_PRIO_VBLANK = 0,
NVKM_INTR_PRIO_NORMAL,
NVKM_INTR_PRIO_NR
};
enum nvkm_intr_type {
NVKM_INTR_SUBDEV = -1, /* lookup vector by requesting subdev, in mapping table. */
NVKM_INTR_VECTOR_0 = 0,
};
struct nvkm_intr {
const struct nvkm_intr_func {
bool (*pending)(struct nvkm_intr *);
void (*unarm)(struct nvkm_intr *);
void (*rearm)(struct nvkm_intr *);
void (*block)(struct nvkm_intr *, int leaf, u32 mask);
void (*allow)(struct nvkm_intr *, int leaf, u32 mask);
void (*reset)(struct nvkm_intr *, int leaf, u32 mask);
} *func;
const struct nvkm_intr_data {
int type; /* enum nvkm_subdev_type (+ve), enum nvkm_intr_type (-ve) */
int inst;
int leaf;
u32 mask; /* 0-terminated. */
bool legacy; /* auto-create "legacy" nvkm_subdev_intr() handler */
} *data;
struct nvkm_subdev *subdev;
int leaves;
u32 *stat;
u32 *mask;
struct list_head head;
};
void nvkm_intr_ctor(struct nvkm_device *);
void nvkm_intr_dtor(struct nvkm_device *);
int nvkm_intr_install(struct nvkm_device *);
void nvkm_intr_unarm(struct nvkm_device *);
void nvkm_intr_rearm(struct nvkm_device *);
int nvkm_intr_add(const struct nvkm_intr_func *, const struct nvkm_intr_data *,
struct nvkm_subdev *, int leaves, struct nvkm_intr *);
void nvkm_intr_block(struct nvkm_subdev *, enum nvkm_intr_type);
void nvkm_intr_allow(struct nvkm_subdev *, enum nvkm_intr_type);
struct nvkm_inth;
typedef irqreturn_t (*nvkm_inth_func)(struct nvkm_inth *);
struct nvkm_inth {
struct nvkm_intr *intr;
int leaf;
u32 mask;
nvkm_inth_func func;
atomic_t allowed;
struct list_head head;
};
int nvkm_inth_add(struct nvkm_intr *, enum nvkm_intr_type, enum nvkm_intr_prio,
struct nvkm_subdev *, nvkm_inth_func, struct nvkm_inth *);
void nvkm_inth_allow(struct nvkm_inth *);
void nvkm_inth_block(struct nvkm_inth *);
#endif

View file

@ -1,8 +1,10 @@
/* SPDX-License-Identifier: MIT */
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_TOP , struct nvkm_top , top)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GSP , struct nvkm_gsp , gsp)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VFN , struct nvkm_vfn , vfn)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_PCI , struct nvkm_pci , pci)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VBIOS , struct nvkm_bios , bios)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_DEVINIT , struct nvkm_devinit , devinit)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_TOP , struct nvkm_top , top)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_PRIVRING, struct nvkm_subdev , privring)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GPIO , struct nvkm_gpio , gpio)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_I2C , struct nvkm_i2c , i2c)
@ -23,7 +25,6 @@ NVKM_LAYOUT_ONCE(NVKM_SUBDEV_VOLT , struct nvkm_volt , volt)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_ICCSENSE, struct nvkm_iccsense, iccsense)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_THERM , struct nvkm_therm , therm)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_CLK , struct nvkm_clk , clk)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_GSP , struct nvkm_gsp , gsp)
NVKM_LAYOUT_INST(NVKM_SUBDEV_IOCTRL , struct nvkm_subdev , ioctrl, 3)
NVKM_LAYOUT_ONCE(NVKM_SUBDEV_FLA , struct nvkm_subdev , fla)

View file

@ -37,6 +37,7 @@ struct nvkm_memory_func {
void (*release)(struct nvkm_memory *);
int (*map)(struct nvkm_memory *, u64 offset, struct nvkm_vmm *,
struct nvkm_vma *, void *argv, u32 argc);
int (*kmap)(struct nvkm_memory *, struct nvkm_memory **);
};
struct nvkm_memory_ptrs {
@ -63,6 +64,7 @@ void nvkm_memory_tags_put(struct nvkm_memory *, struct nvkm_device *,
#define nvkm_memory_boot(p,v) (p)->func->boot((p),(v))
#define nvkm_memory_map(p,o,vm,va,av,ac) \
(p)->func->map((p),(o),(vm),(va),(av),(ac))
#define nvkm_memory_kmap(p,i) ((p)->func->kmap ? (p)->func->kmap((p), (i)) : -ENOSYS)
/* accessor macros - kmap()/done() must bracket use of the other accessor
* macros to guarantee correct behaviour across all chipsets

View file

@ -1,39 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_NOTIFY_H__
#define __NVKM_NOTIFY_H__
#include <core/os.h>
struct nvkm_object;
struct nvkm_notify {
struct nvkm_event *event;
struct list_head head;
#define NVKM_NOTIFY_USER 0
#define NVKM_NOTIFY_WORK 1
unsigned long flags;
int block;
#define NVKM_NOTIFY_DROP 0
#define NVKM_NOTIFY_KEEP 1
int (*func)(struct nvkm_notify *);
/* set by nvkm_event ctor */
u32 types;
int index;
u32 size;
struct work_struct work;
/* this is const for a *very* good reason - the data might be on the
* stack from an irq handler. if you're not core/notify.c then you
* should probably think twice before casting it away...
*/
const void *data;
};
int nvkm_notify_init(struct nvkm_object *, struct nvkm_event *,
int (*func)(struct nvkm_notify *), bool work,
void *data, u32 size, u32 reply,
struct nvkm_notify *);
void nvkm_notify_fini(struct nvkm_notify *);
void nvkm_notify_get(struct nvkm_notify *);
void nvkm_notify_put(struct nvkm_notify *);
void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size);
#endif

View file

@ -4,6 +4,7 @@
#include <core/oclass.h>
struct nvkm_event;
struct nvkm_gpuobj;
struct nvkm_uevent;
struct nvkm_object {
const struct nvkm_object_func *func;
@ -43,6 +44,7 @@ struct nvkm_object_func {
int (*bind)(struct nvkm_object *, struct nvkm_gpuobj *, int align,
struct nvkm_gpuobj **);
int (*sclass)(struct nvkm_object *, int index, struct nvkm_oclass *);
int (*uevent)(struct nvkm_object *, void *argv, u32 argc, struct nvkm_uevent *);
};
void nvkm_object_ctor(const struct nvkm_object_func *,

View file

@ -34,4 +34,24 @@ nvkm_blob_dtor(struct nvkm_blob *blob)
blob->data = NULL;
blob->size = 0;
}
#define nvkm_list_find_next(p,h,m,c) ({ \
typeof(p) _p = NULL; \
list_for_each_entry_continue(p, (h), m) { \
if (c) { \
_p = p; \
break; \
} \
} \
_p; \
})
#define nvkm_list_find(p,h,m,c) \
(p = container_of((h), typeof(*p), m), nvkm_list_find_next(p, (h), m, (c)))
#define nvkm_list_foreach(p,h,m,c) \
for (p = nvkm_list_find(p, (h), m, (c)); p; p = nvkm_list_find_next(p, (h), m, (c)))
/*FIXME: remove after */
#define nvkm_fifo_chan nvkm_chan
#define nvkm_fifo_chan_func nvkm_chan_func
#define nvkm_fifo_cgrp nvkm_cgrp
#endif

View file

@ -17,10 +17,19 @@ struct nvkm_subdev {
struct nvkm_device *device;
enum nvkm_subdev_type type;
int inst;
char name[16];
u32 debug;
struct list_head head;
struct {
refcount_t refcount;
struct mutex mutex;
bool enabled;
} use;
struct nvkm_inth inth;
struct list_head head;
void **pself;
bool oneinit;
};
@ -38,22 +47,41 @@ struct nvkm_subdev_func {
extern const char *nvkm_subdev_type[NVKM_SUBDEV_NR];
int nvkm_subdev_new_(const struct nvkm_subdev_func *, struct nvkm_device *, enum nvkm_subdev_type,
int inst, struct nvkm_subdev **);
void nvkm_subdev_ctor(const struct nvkm_subdev_func *, struct nvkm_device *,
enum nvkm_subdev_type, int inst, struct nvkm_subdev *);
void __nvkm_subdev_ctor(const struct nvkm_subdev_func *, struct nvkm_device *,
enum nvkm_subdev_type, int inst, struct nvkm_subdev *);
static inline void
nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev)
{
__nvkm_subdev_ctor(func, device, type, inst, subdev);
mutex_init(&subdev->use.mutex);
}
void nvkm_subdev_disable(struct nvkm_device *, enum nvkm_subdev_type, int inst);
void nvkm_subdev_del(struct nvkm_subdev **);
int nvkm_subdev_ref(struct nvkm_subdev *);
void nvkm_subdev_unref(struct nvkm_subdev *);
int nvkm_subdev_preinit(struct nvkm_subdev *);
int nvkm_subdev_oneinit(struct nvkm_subdev *);
int nvkm_subdev_init(struct nvkm_subdev *);
int nvkm_subdev_fini(struct nvkm_subdev *, bool suspend);
int nvkm_subdev_info(struct nvkm_subdev *, u64, u64 *);
void nvkm_subdev_intr(struct nvkm_subdev *);
/* subdev logging */
#define nvkm_printk_(s,l,p,f,a...) do { \
const struct nvkm_subdev *_subdev = (s); \
if (CONFIG_NOUVEAU_DEBUG >= (l) && _subdev->debug >= (l)) \
dev_##p(_subdev->device->dev, "%s: "f, _subdev->name, ##a); \
#define nvkm_printk_ok(s,u,l) \
((CONFIG_NOUVEAU_DEBUG >= (l)) && ((s)->debug >= (l) || ((u) && (u)->debug >= (l))))
#define nvkm_printk___(s,u,l,p,f,a...) do { \
if (nvkm_printk_ok((s), (u), (l))) { \
if ((u) && (u) != (s)) \
dev_##p((s)->device->dev, "%s(%s):"f, (s)->name, (u)->name, ##a); \
else \
dev_##p((s)->device->dev, "%s:"f, (s)->name, ##a); \
} \
} while(0)
#define nvkm_printk__(s,l,p,f,a...) nvkm_printk___((s), (s), (l), p, f, ##a)
#define nvkm_printk_(s,l,p,f,a...) nvkm_printk__((s), (l), p, " "f, ##a)
#define nvkm_printk(s,l,p,f,a...) nvkm_printk_((s), NV_DBG_##l, p, f, ##a)
#define nvkm_fatal(s,f,a...) nvkm_printk((s), FATAL, crit, f, ##a)
#define nvkm_error(s,f,a...) nvkm_printk((s), ERROR, err, f, ##a)

View file

@ -8,7 +8,6 @@ struct nvkm_device_tegra {
const struct nvkm_device_tegra_func *func;
struct nvkm_device device;
struct platform_device *pdev;
int irq;
struct reset_control *rst;
struct clk *clk;

View file

@ -12,4 +12,6 @@ int gp100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n
int gp102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
int gv100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
int tu102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
int ga100_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
int ga102_ce_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_engine **);
#endif

View file

@ -16,6 +16,7 @@ struct nvkm_disp {
struct list_head conns;
struct nvkm_event hpd;
#define NVKM_DISP_HEAD_EVENT_VBLANK BIT(0)
struct nvkm_event vblank;
struct {
@ -31,13 +32,7 @@ struct nvkm_disp {
struct {
unsigned long mask;
int nr;
} wndw, head, dac;
struct {
unsigned long mask;
int nr;
u32 lvdsconf;
} sor;
} wndw, head, dac, sor;
struct {
unsigned long mask;

View file

@ -16,15 +16,16 @@ enum nvkm_falcon_dmaidx {
struct nvkm_falcon {
const struct nvkm_falcon_func *func;
const struct nvkm_subdev *owner;
struct nvkm_subdev *owner;
const char *name;
u32 addr;
u32 addr2;
struct mutex mutex;
struct mutex dmem_mutex;
bool oneinit;
const struct nvkm_subdev *user;
struct nvkm_subdev *user;
u8 version;
u8 secret;
@ -50,13 +51,42 @@ struct nvkm_falcon {
struct nvkm_engine engine;
};
int nvkm_falcon_get(struct nvkm_falcon *, const struct nvkm_subdev *);
void nvkm_falcon_put(struct nvkm_falcon *, const struct nvkm_subdev *);
int nvkm_falcon_get(struct nvkm_falcon *, struct nvkm_subdev *);
void nvkm_falcon_put(struct nvkm_falcon *, struct nvkm_subdev *);
int nvkm_falcon_new_(const struct nvkm_falcon_func *, struct nvkm_device *,
enum nvkm_subdev_type, int inst, bool enable, u32 addr, struct nvkm_engine **);
struct nvkm_falcon_func {
int (*disable)(struct nvkm_falcon *);
int (*enable)(struct nvkm_falcon *);
int (*select)(struct nvkm_falcon *);
u32 addr2;
bool reset_pmc;
int (*reset_eng)(struct nvkm_falcon *);
int (*reset_prep)(struct nvkm_falcon *);
int (*reset_wait_mem_scrubbing)(struct nvkm_falcon *);
u32 debug;
void (*bind_inst)(struct nvkm_falcon *, int target, u64 addr);
int (*bind_stat)(struct nvkm_falcon *, bool intr);
bool bind_intr;
const struct nvkm_falcon_func_pio *imem_pio;
const struct nvkm_falcon_func_dma *imem_dma;
const struct nvkm_falcon_func_pio *dmem_pio;
const struct nvkm_falcon_func_dma *dmem_dma;
u32 emem_addr;
const struct nvkm_falcon_func_pio *emem_pio;
struct {
u32 head;
u32 tail;
u32 stride;
} cmdq, msgq;
struct {
u32 *data;
u32 size;
@ -66,29 +96,11 @@ struct nvkm_falcon_func {
u32 size;
} data;
void (*init)(struct nvkm_falcon *);
void (*intr)(struct nvkm_falcon *, struct nvkm_fifo_chan *);
u32 debug;
u32 fbif;
void (*intr)(struct nvkm_falcon *, struct nvkm_chan *);
void (*load_imem)(struct nvkm_falcon *, void *, u32, u32, u16, u8, bool);
void (*load_dmem)(struct nvkm_falcon *, void *, u32, u32, u8);
void (*read_dmem)(struct nvkm_falcon *, u32, u32, u8, void *);
u32 emem_addr;
void (*bind_context)(struct nvkm_falcon *, struct nvkm_memory *);
int (*wait_for_halt)(struct nvkm_falcon *, u32);
int (*clear_interrupt)(struct nvkm_falcon *, u32);
void (*set_start_addr)(struct nvkm_falcon *, u32 start_addr);
void (*start)(struct nvkm_falcon *);
int (*enable)(struct nvkm_falcon *falcon);
void (*disable)(struct nvkm_falcon *falcon);
int (*reset)(struct nvkm_falcon *);
struct {
u32 head;
u32 tail;
u32 stride;
} cmdq, msgq;
struct nvkm_sclass sclass[];
};
@ -116,13 +128,5 @@ nvkm_falcon_mask(struct nvkm_falcon *falcon, u32 addr, u32 mask, u32 val)
void nvkm_falcon_load_imem(struct nvkm_falcon *, void *, u32, u32, u16, u8,
bool);
void nvkm_falcon_load_dmem(struct nvkm_falcon *, void *, u32, u32, u8);
void nvkm_falcon_read_dmem(struct nvkm_falcon *, u32, u32, u8, void *);
void nvkm_falcon_bind_context(struct nvkm_falcon *, struct nvkm_memory *);
void nvkm_falcon_set_start_addr(struct nvkm_falcon *, u32);
void nvkm_falcon_start(struct nvkm_falcon *);
int nvkm_falcon_wait_for_halt(struct nvkm_falcon *, u32);
int nvkm_falcon_clear_interrupt(struct nvkm_falcon *, u32);
int nvkm_falcon_enable(struct nvkm_falcon *);
void nvkm_falcon_disable(struct nvkm_falcon *);
int nvkm_falcon_reset(struct nvkm_falcon *);
#endif

View file

@ -6,56 +6,76 @@
#include <core/event.h>
struct nvkm_fault_data;
#define NVKM_FIFO_CHID_NR 4096
#define NVKM_FIFO_ENGN_NR 16
struct nvkm_fifo_engn {
struct nvkm_object *object;
int refcount;
int usecount;
};
struct nvkm_chan {
const struct nvkm_chan_func *func;
char name[64];
struct nvkm_cgrp *cgrp;
int runq;
struct nvkm_fifo_chan {
const struct nvkm_fifo_chan_func *func;
struct nvkm_fifo *fifo;
u32 engm;
struct nvkm_object object;
struct list_head head;
u16 chid;
struct nvkm_gpuobj *inst;
struct nvkm_gpuobj *push;
struct nvkm_vmm *vmm;
u64 addr;
u32 size;
struct nvkm_gpuobj *push;
int id;
struct nvkm_fifo_engn engn[NVKM_FIFO_ENGN_NR];
struct {
struct nvkm_memory *mem;
u32 base;
} userd;
u32 ramfc_offset;
struct nvkm_gpuobj *ramfc;
struct nvkm_gpuobj *cache;
struct nvkm_gpuobj *eng;
struct nvkm_gpuobj *pgd;
struct nvkm_ramht *ramht;
spinlock_t lock;
atomic_t blocked;
atomic_t errored;
struct list_head cctxs;
struct list_head head;
};
struct nvkm_chan *nvkm_chan_get_chid(struct nvkm_engine *, int id, unsigned long *irqflags);
struct nvkm_chan *nvkm_chan_get_inst(struct nvkm_engine *, u64 inst, unsigned long *irqflags);
void nvkm_chan_put(struct nvkm_chan **, unsigned long irqflags);
struct nvkm_fifo {
const struct nvkm_fifo_func *func;
struct nvkm_engine engine;
DECLARE_BITMAP(mask, NVKM_FIFO_CHID_NR);
int nr;
struct list_head chan;
struct nvkm_chid *chid;
struct nvkm_chid *cgid;
struct list_head runqs;
struct list_head runls;
struct {
#define NVKM_FIFO_NONSTALL_EVENT BIT(0)
struct nvkm_event event;
struct nvkm_inth intr;
} nonstall;
struct {
u32 chan_msec;
} timeout;
struct {
struct nvkm_memory *mem;
struct nvkm_vma *bar1;
} userd;
spinlock_t lock;
struct mutex mutex;
struct nvkm_event uevent; /* async user trigger */
struct nvkm_event kevent; /* channel killed */
};
void nvkm_fifo_fault(struct nvkm_fifo *, struct nvkm_fault_data *);
void nvkm_fifo_pause(struct nvkm_fifo *, unsigned long *);
void nvkm_fifo_start(struct nvkm_fifo *, unsigned long *);
void nvkm_fifo_chan_put(struct nvkm_fifo *, unsigned long flags,
struct nvkm_fifo_chan **);
struct nvkm_fifo_chan *
nvkm_fifo_chan_inst(struct nvkm_fifo *, u64 inst, unsigned long *flags);
struct nvkm_fifo_chan *
nvkm_fifo_chan_chid(struct nvkm_fifo *, int chid, unsigned long *flags);
bool nvkm_fifo_ctxsw_in_progress(struct nvkm_engine *);
int nv04_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int nv10_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
@ -63,6 +83,7 @@ int nv17_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int nv40_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int nv50_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int g84_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int g98_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gf100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gk104_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gk110_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
@ -70,10 +91,9 @@ int gk208_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gk20a_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gm107_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gm200_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gm20b_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gp100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gp10b_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int gv100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int tu102_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int ga100_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
int ga102_fifo_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fifo **);
#endif

View file

@ -54,4 +54,5 @@ int gp108_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n
int gp10b_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **);
int gv100_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **);
int tu102_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **);
int ga102_gr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_gr **);
#endif

View file

@ -12,4 +12,5 @@ struct nvkm_nvdec {
};
int gm107_nvdec_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_nvdec **);
int ga102_nvdec_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_nvdec **);
#endif

View file

@ -10,15 +10,18 @@ struct nvkm_sec2 {
struct nvkm_engine engine;
struct nvkm_falcon falcon;
atomic_t running;
atomic_t initmsg;
struct nvkm_falcon_qmgr *qmgr;
struct nvkm_falcon_cmdq *cmdq;
struct nvkm_falcon_msgq *msgq;
struct work_struct work;
bool initmsg_received;
};
int gp102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
int gp108_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
int tu102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
int ga102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
#endif

View file

@ -36,7 +36,7 @@ struct nvkm_acr {
const struct nvkm_acr_func *func;
struct nvkm_subdev subdev;
struct list_head hsfw, hsf;
struct list_head hsfw;
struct list_head lsfw, lsf;
u64 managed_falcons;
@ -50,6 +50,7 @@ struct nvkm_acr {
struct nvkm_vmm *vmm;
bool done;
struct nvkm_acr_lsf *rtos;
const struct firmware *wpr_fw;
bool wpr_comp;
@ -64,7 +65,9 @@ int gm20b_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gp102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
int gp108_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
int gp10b_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
int gv100_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
int tu102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
int ga102_acr_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_acr **);
struct nvkm_acr_lsfw {
const struct nvkm_acr_lsf_func *func;
@ -77,6 +80,7 @@ struct nvkm_acr_lsfw {
const struct firmware *sig;
bool secure_bootloader;
u32 bootloader_size;
u32 bootloader_imem_offset;
@ -87,10 +91,19 @@ struct nvkm_acr_lsfw {
u32 app_resident_code_size;
u32 app_resident_data_offset;
u32 app_resident_data_size;
u32 app_imem_offset;
u32 app_dmem_offset;
u32 ucode_size;
u32 data_size;
u32 fuse_ver;
u32 engine_id;
u32 ucode_id;
u32 sig_size;
u32 sig_nr;
u8 *sigs;
struct {
u32 lsb;
u32 img;
@ -105,10 +118,10 @@ struct nvkm_acr_lsf_func {
#define NVKM_ACR_LSF_DMACTL_REQ_CTX 0x00000004
#define NVKM_ACR_LSF_FORCE_PRIV_LOAD 0x00000008
u32 flags;
u32 bl_entry;
u32 bld_size;
void (*bld_write)(struct nvkm_acr *, u32 bld, struct nvkm_acr_lsfw *);
void (*bld_patch)(struct nvkm_acr *, u32 bld, s64 adjust);
int (*boot)(struct nvkm_falcon *);
u64 bootstrap_falcons;
int (*bootstrap_falcon)(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
int (*bootstrap_multiple_falcons)(struct nvkm_falcon *, u32 mask);
@ -122,8 +135,20 @@ int
nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *, struct nvkm_falcon *,
enum nvkm_acr_lsf_id, const char *path,
int ver, const struct nvkm_acr_lsf_func *);
int
nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *, struct nvkm_falcon *,
enum nvkm_acr_lsf_id, const char *path,
int ver, const struct nvkm_acr_lsf_func *);
int
nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *, struct nvkm_falcon *,
enum nvkm_acr_lsf_id, const char *path,
int ver, const struct nvkm_acr_lsf_func *);
int
nvkm_acr_lsfw_load_bl_sig_net(struct nvkm_subdev *, struct nvkm_falcon *,
enum nvkm_acr_lsf_id, const char *path,
int ver, const struct nvkm_acr_lsf_func *,
const void *, u32, const void *, u32);
#endif

View file

@ -2,18 +2,21 @@
#define __NVKM_FAULT_H__
#include <core/subdev.h>
#include <core/event.h>
#include <core/notify.h>
struct nvkm_fault {
const struct nvkm_fault_func *func;
struct nvkm_subdev subdev;
struct nvkm_inth info_fault;
struct nvkm_fault_buffer *buffer[2];
int buffer_nr;
#define NVKM_FAULT_BUFFER_EVENT_PENDING BIT(0)
struct nvkm_event event;
struct nvkm_notify nrpfb;
struct nvkm_event_ntfy nrpfb;
struct work_struct nrpfb_work;
struct nvkm_device_oclass user;
};

View file

@ -35,6 +35,11 @@ struct nvkm_fb {
struct nvkm_blob vpr_scrubber;
struct {
struct page *flush_page;
dma_addr_t flush_page_addr;
} sysmem;
struct nvkm_ram *ram;
struct {
@ -53,6 +58,8 @@ struct nvkm_fb {
struct nvkm_memory *mmu_wr;
};
int nvkm_fb_mem_unlock(struct nvkm_fb *);
void nvkm_fb_tile_init(struct nvkm_fb *, int region, u32 addr, u32 size,
u32 pitch, u32 flags, struct nvkm_fb_tile *);
void nvkm_fb_tile_fini(struct nvkm_fb *, int region, struct nvkm_fb_tile *);

View file

@ -8,9 +8,6 @@
#include <subdev/bios/gpio.h>
struct nvkm_gpio_ntfy_req {
#define NVKM_GPIO_HI 0x01
#define NVKM_GPIO_LO 0x02
#define NVKM_GPIO_TOGGLED 0x03
u8 mask;
u8 line;
};
@ -23,6 +20,9 @@ struct nvkm_gpio {
const struct nvkm_gpio_func *func;
struct nvkm_subdev subdev;
#define NVKM_GPIO_HI BIT(0)
#define NVKM_GPIO_LO BIT(1)
#define NVKM_GPIO_TOGGLED (NVKM_GPIO_HI | NVKM_GPIO_LO)
struct nvkm_event event;
};

View file

@ -5,9 +5,12 @@
#include <core/falcon.h>
struct nvkm_gsp {
const struct nvkm_gsp_func *func;
struct nvkm_subdev subdev;
struct nvkm_falcon falcon;
};
int gv100_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **);
int ga102_gsp_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **);
#endif

View file

@ -7,20 +7,6 @@
#include <subdev/bios.h>
#include <subdev/bios/i2c.h>
struct nvkm_i2c_ntfy_req {
#define NVKM_I2C_PLUG 0x01
#define NVKM_I2C_UNPLUG 0x02
#define NVKM_I2C_IRQ 0x04
#define NVKM_I2C_DONE 0x08
#define NVKM_I2C_ANY 0x0f
u8 mask;
u8 port;
};
struct nvkm_i2c_ntfy_rep {
u8 mask;
};
struct nvkm_i2c_bus_probe {
struct i2c_board_info dev;
u8 udelay; /* set to 0 to use the standard delay */
@ -79,6 +65,11 @@ struct nvkm_i2c {
struct list_head bus;
struct list_head aux;
#define NVKM_I2C_PLUG BIT(0)
#define NVKM_I2C_UNPLUG BIT(1)
#define NVKM_I2C_IRQ BIT(2)
#define NVKM_I2C_DONE BIT(3)
#define NVKM_I2C_ANY (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG | NVKM_I2C_IRQ | NVKM_I2C_DONE)
struct nvkm_event event;
};

View file

@ -28,7 +28,7 @@ u32 nvkm_instmem_rd32(struct nvkm_instmem *, u32 addr);
void nvkm_instmem_wr32(struct nvkm_instmem *, u32 addr, u32 data);
int nvkm_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero,
struct nvkm_memory **);
int nvkm_instobj_wrap(struct nvkm_device *, struct nvkm_memory *, struct nvkm_memory **);
int nv04_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_instmem **);
int nv40_instmem_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_instmem **);

View file

@ -4,7 +4,8 @@
#include <core/subdev.h>
#include <core/mm.h>
#define NVKM_LTC_MAX_ZBC_CNT 16
#define NVKM_LTC_MAX_ZBC_COLOR_CNT 32
#define NVKM_LTC_MAX_ZBC_DEPTH_CNT 16
struct nvkm_ltc {
const struct nvkm_ltc_func *func;
@ -18,11 +19,13 @@ struct nvkm_ltc {
u32 tag_base;
struct nvkm_memory *tag_ram;
int zbc_min;
int zbc_max;
u32 zbc_color[NVKM_LTC_MAX_ZBC_CNT][4];
u32 zbc_depth[NVKM_LTC_MAX_ZBC_CNT];
u32 zbc_stencil[NVKM_LTC_MAX_ZBC_CNT];
int zbc_color_min;
int zbc_color_max;
u32 zbc_color[NVKM_LTC_MAX_ZBC_COLOR_CNT][4];
int zbc_depth_min;
int zbc_depth_max;
u32 zbc_depth[NVKM_LTC_MAX_ZBC_DEPTH_CNT];
u32 zbc_stencil[NVKM_LTC_MAX_ZBC_DEPTH_CNT];
};
void nvkm_ltc_tags_clear(struct nvkm_device *, u32 first, u32 count);
@ -41,4 +44,5 @@ int gm200_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gp100_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **);
int gp102_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **);
int gp10b_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **);
int ga102_ltc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_ltc **);
#endif

View file

@ -6,15 +6,14 @@
struct nvkm_mc {
const struct nvkm_mc_func *func;
struct nvkm_subdev subdev;
struct nvkm_intr intr;
};
void nvkm_mc_enable(struct nvkm_device *, enum nvkm_subdev_type, int);
void nvkm_mc_disable(struct nvkm_device *, enum nvkm_subdev_type, int);
bool nvkm_mc_enabled(struct nvkm_device *, enum nvkm_subdev_type, int);
void nvkm_mc_reset(struct nvkm_device *, enum nvkm_subdev_type, int);
void nvkm_mc_intr(struct nvkm_device *, bool *handled);
void nvkm_mc_intr_unarm(struct nvkm_device *);
void nvkm_mc_intr_rearm(struct nvkm_device *);
void nvkm_mc_intr_mask(struct nvkm_device *, enum nvkm_subdev_type, int, bool enable);
void nvkm_mc_unk260(struct nvkm_device *, u32 data);
@ -31,6 +30,5 @@ int gk104_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n
int gk20a_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
int gp100_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
int gp10b_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
int tu102_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
int ga100_mc_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_mc **);
#endif

View file

@ -13,7 +13,6 @@ struct nvkm_pci {
const struct nvkm_pci_func *func;
struct nvkm_subdev subdev;
struct pci_dev *pdev;
int irq;
struct {
struct agp_bridge_data *bridge;
@ -38,6 +37,7 @@ void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data);
void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data);
u32 nvkm_pci_mask(struct nvkm_pci *, u16 addr, u32 mask, u32 value);
void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow);
void nvkm_pci_msi_rearm(struct nvkm_device *);
int nv04_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **);
int nv40_pci_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pci **);

View file

@ -21,6 +21,7 @@ struct nvkm_top_device {
struct list_head head;
};
int nvkm_top_parse(struct nvkm_device *);
u32 nvkm_top_addr(struct nvkm_device *, enum nvkm_subdev_type, int);
u32 nvkm_top_reset(struct nvkm_device *, enum nvkm_subdev_type, int);
u32 nvkm_top_intr_mask(struct nvkm_device *, enum nvkm_subdev_type, int);

View file

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_VFN_H__
#define __NVKM_VFN_H__
#include <core/subdev.h>
struct nvkm_vfn {
const struct nvkm_vfn_func *func;
struct nvkm_subdev subdev;
struct {
u32 priv;
u32 user;
} addr;
struct nvkm_intr intr;
struct nvkm_device_oclass user;
};
int gv100_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **);
int tu102_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **);
int ga100_vfn_new(struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_vfn **);
#endif

View file

@ -27,7 +27,6 @@
#include <nvif/ioctl.h>
#include <nvif/class.h>
#include <nvif/cl0002.h>
#include <nvif/cla06f.h>
#include <nvif/unpack.h>
#include "nouveau_drv.h"
@ -253,7 +252,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
struct nouveau_abi16_chan *chan;
struct nvif_device *device;
u64 engine;
u64 engine, runm;
int ret;
if (unlikely(!abi16))
@ -263,6 +262,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
return nouveau_abi16_put(abi16, -ENODEV);
device = &abi16->device;
engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR;
/* hack to allow channel engine type specification on kepler */
if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
@ -276,19 +276,18 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
default:
return nouveau_abi16_put(abi16, -ENOSYS);
}
} else {
engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR;
}
if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_CE)
engine = nvif_fifo_runlist(device, engine);
else
engine = nvif_fifo_runlist_ce(device);
init->fb_ctxdma_handle = engine;
init->tt_ctxdma_handle = 0;
init->fb_ctxdma_handle = 0;
init->tt_ctxdma_handle = 0;
}
}
if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_CE)
runm = nvif_fifo_runlist(device, engine);
else
runm = nvif_fifo_runlist_ce(device);
if (!runm || init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
return nouveau_abi16_put(abi16, -EINVAL);
/* allocate "abi16 channel" data and make up a handle for it */
@ -300,8 +299,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
list_add(&chan->head, &abi16->channels);
/* create channel object and initialise dma and fence management */
ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle,
init->tt_ctxdma_handle, false, &chan->chan);
ret = nouveau_channel_new(drm, device, false, runm, init->fb_ctxdma_handle,
init->tt_ctxdma_handle, &chan->chan);
if (ret)
goto done;

View file

@ -856,6 +856,9 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
int (*init)(struct nouveau_channel *, u32 handle);
} _methods[] = {
{ "COPY", 4, 0xc7b5, nve0_bo_move_copy, nve0_bo_move_init },
{ "GRCE", 0, 0xc7b5, nve0_bo_move_copy, nvc0_bo_move_init },
{ "COPY", 4, 0xc6b5, nve0_bo_move_copy, nve0_bo_move_init },
{ "GRCE", 0, 0xc6b5, nve0_bo_move_copy, nvc0_bo_move_init },
{ "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init },
{ "GRCE", 0, 0xc5b5, nve0_bo_move_copy, nvc0_bo_move_init },
{ "COPY", 4, 0xc3b5, nve0_bo_move_copy, nve0_bo_move_init },

View file

@ -25,12 +25,7 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
#include <nvif/cl006b.h>
#include <nvif/cl506f.h>
#include <nvif/cl906f.h>
#include <nvif/cla06f.h>
#include <nvif/clc36f.h>
#include <nvif/ioctl.h>
#include <nvif/if0020.h>
#include "nouveau_drv.h"
#include "nouveau_dma.h"
@ -46,15 +41,17 @@ int nouveau_vram_pushbuf;
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
static int
nouveau_channel_killed(struct nvif_notify *ntfy)
nouveau_channel_killed(struct nvif_event *event, void *repv, u32 repc)
{
struct nouveau_channel *chan = container_of(ntfy, typeof(*chan), kill);
struct nouveau_channel *chan = container_of(event, typeof(*chan), kill);
struct nouveau_cli *cli = (void *)chan->user.client;
NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid);
atomic_set(&chan->killed, 1);
if (chan->fence)
nouveau_fence_context_kill(chan->fence, -ENODEV);
return NVIF_NOTIFY_DROP;
return NVIF_EVENT_DROP;
}
int
@ -96,8 +93,9 @@ nouveau_channel_del(struct nouveau_channel **pchan)
nvif_object_dtor(&chan->nvsw);
nvif_object_dtor(&chan->gart);
nvif_object_dtor(&chan->vram);
nvif_notify_dtor(&chan->kill);
nvif_event_dtor(&chan->kill);
nvif_object_dtor(&chan->user);
nvif_mem_dtor(&chan->mem_userd);
nvif_object_dtor(&chan->push.ctxdma);
nouveau_vma_del(&chan->push.vma);
nouveau_bo_unmap(chan->push.buffer);
@ -247,134 +245,113 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
}
static int
nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
u64 runlist, bool priv, struct nouveau_channel **pchan)
nouveau_channel_ctor(struct nouveau_drm *drm, struct nvif_device *device, bool priv, u64 runm,
struct nouveau_channel **pchan)
{
static const u16 oclasses[] = { AMPERE_CHANNEL_GPFIFO_B,
TURING_CHANNEL_GPFIFO_A,
VOLTA_CHANNEL_GPFIFO_A,
PASCAL_CHANNEL_GPFIFO_A,
MAXWELL_CHANNEL_GPFIFO_A,
KEPLER_CHANNEL_GPFIFO_B,
KEPLER_CHANNEL_GPFIFO_A,
FERMI_CHANNEL_GPFIFO,
G82_CHANNEL_GPFIFO,
NV50_CHANNEL_GPFIFO,
0 };
const u16 *oclass = oclasses;
union {
struct nv50_channel_gpfifo_v0 nv50;
struct fermi_channel_gpfifo_v0 fermi;
struct kepler_channel_gpfifo_a_v0 kepler;
struct volta_channel_gpfifo_a_v0 volta;
static const struct {
s32 oclass;
int version;
} hosts[] = {
{ AMPERE_CHANNEL_GPFIFO_B, 0 },
{ AMPERE_CHANNEL_GPFIFO_A, 0 },
{ TURING_CHANNEL_GPFIFO_A, 0 },
{ VOLTA_CHANNEL_GPFIFO_A, 0 },
{ PASCAL_CHANNEL_GPFIFO_A, 0 },
{ MAXWELL_CHANNEL_GPFIFO_A, 0 },
{ KEPLER_CHANNEL_GPFIFO_B, 0 },
{ KEPLER_CHANNEL_GPFIFO_A, 0 },
{ FERMI_CHANNEL_GPFIFO , 0 },
{ G82_CHANNEL_GPFIFO , 0 },
{ NV50_CHANNEL_GPFIFO , 0 },
{ NV40_CHANNEL_DMA , 0 },
{ NV17_CHANNEL_DMA , 0 },
{ NV10_CHANNEL_DMA , 0 },
{ NV03_CHANNEL_DMA , 0 },
{}
};
struct {
struct nvif_chan_v0 chan;
char name[TASK_COMM_LEN+16];
} args;
struct nouveau_cli *cli = (void *)device->object.client;
struct nouveau_channel *chan;
u32 size;
int ret;
const u64 plength = 0x10000;
const u64 ioffset = plength;
const u64 ilength = 0x02000;
char name[TASK_COMM_LEN];
int cid, ret;
u64 size;
cid = nvif_mclass(&device->object, hosts);
if (cid < 0)
return cid;
if (hosts[cid].oclass < NV50_CHANNEL_GPFIFO)
size = plength;
else
size = ioffset + ilength;
/* allocate dma push buffer */
ret = nouveau_channel_prep(drm, device, 0x12000, &chan);
ret = nouveau_channel_prep(drm, device, size, &chan);
*pchan = chan;
if (ret)
return ret;
/* create channel object */
do {
if (oclass[0] >= VOLTA_CHANNEL_GPFIFO_A) {
args.volta.version = 0;
args.volta.ilength = 0x02000;
args.volta.ioffset = 0x10000 + chan->push.addr;
args.volta.runlist = runlist;
args.volta.vmm = nvif_handle(&chan->vmm->vmm.object);
args.volta.priv = priv;
size = sizeof(args.volta);
} else
if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
args.kepler.version = 0;
args.kepler.ilength = 0x02000;
args.kepler.ioffset = 0x10000 + chan->push.addr;
args.kepler.runlist = runlist;
args.kepler.vmm = nvif_handle(&chan->vmm->vmm.object);
args.kepler.priv = priv;
size = sizeof(args.kepler);
} else
if (oclass[0] >= FERMI_CHANNEL_GPFIFO) {
args.fermi.version = 0;
args.fermi.ilength = 0x02000;
args.fermi.ioffset = 0x10000 + chan->push.addr;
args.fermi.vmm = nvif_handle(&chan->vmm->vmm.object);
size = sizeof(args.fermi);
} else {
args.nv50.version = 0;
args.nv50.ilength = 0x02000;
args.nv50.ioffset = 0x10000 + chan->push.addr;
args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma);
args.nv50.vmm = nvif_handle(&chan->vmm->vmm.object);
size = sizeof(args.nv50);
}
args.chan.version = 0;
args.chan.namelen = sizeof(args.name);
args.chan.runlist = __ffs64(runm);
args.chan.runq = 0;
args.chan.priv = priv;
args.chan.devm = BIT(0);
if (hosts[cid].oclass < NV50_CHANNEL_GPFIFO) {
args.chan.vmm = 0;
args.chan.ctxdma = nvif_handle(&chan->push.ctxdma);
args.chan.offset = chan->push.addr;
args.chan.length = 0;
} else {
args.chan.vmm = nvif_handle(&chan->vmm->vmm.object);
if (hosts[cid].oclass < FERMI_CHANNEL_GPFIFO)
args.chan.ctxdma = nvif_handle(&chan->push.ctxdma);
else
args.chan.ctxdma = 0;
args.chan.offset = ioffset + chan->push.addr;
args.chan.length = ilength;
}
args.chan.huserd = 0;
args.chan.ouserd = 0;
ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0,
*oclass++, &args, size, &chan->user);
if (ret == 0) {
if (chan->user.oclass >= VOLTA_CHANNEL_GPFIFO_A) {
chan->chid = args.volta.chid;
chan->inst = args.volta.inst;
chan->token = args.volta.token;
} else
if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) {
chan->chid = args.kepler.chid;
chan->inst = args.kepler.inst;
} else
if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) {
chan->chid = args.fermi.chid;
} else {
chan->chid = args.nv50.chid;
}
/* allocate userd */
if (hosts[cid].oclass >= VOLTA_CHANNEL_GPFIFO_A) {
ret = nvif_mem_ctor(&cli->mmu, "abi16ChanUSERD", NVIF_CLASS_MEM_GF100,
NVIF_MEM_VRAM | NVIF_MEM_COHERENT | NVIF_MEM_MAPPABLE,
0, PAGE_SIZE, NULL, 0, &chan->mem_userd);
if (ret)
return ret;
}
} while (*oclass);
nouveau_channel_del(pchan);
return ret;
}
args.chan.huserd = nvif_handle(&chan->mem_userd.object);
args.chan.ouserd = 0;
static int
nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device,
struct nouveau_channel **pchan)
{
static const u16 oclasses[] = { NV40_CHANNEL_DMA,
NV17_CHANNEL_DMA,
NV10_CHANNEL_DMA,
NV03_CHANNEL_DMA,
0 };
const u16 *oclass = oclasses;
struct nv03_channel_dma_v0 args;
struct nouveau_channel *chan;
int ret;
chan->userd = &chan->mem_userd.object;
} else {
chan->userd = &chan->user;
}
/* allocate dma push buffer */
ret = nouveau_channel_prep(drm, device, 0x10000, &chan);
*pchan = chan;
if (ret)
get_task_comm(name, current);
snprintf(args.name, sizeof(args.name), "%s[%d]", name, task_pid_nr(current));
ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0, hosts[cid].oclass,
&args, sizeof(args), &chan->user);
if (ret) {
nouveau_channel_del(pchan);
return ret;
}
/* create channel object */
args.version = 0;
args.pushbuf = nvif_handle(&chan->push.ctxdma);
args.offset = chan->push.addr;
do {
ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0,
*oclass++, &args, sizeof(args),
&chan->user);
if (ret == 0) {
chan->chid = args.chid;
return ret;
}
} while (ret && *oclass);
nouveau_channel_del(pchan);
return ret;
chan->runlist = args.chan.runlist;
chan->chid = args.chan.chid;
chan->inst = args.chan.inst;
chan->token = args.chan.token;
return 0;
}
static int
@ -385,18 +362,24 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
struct nv_dma_v0 args = {};
int ret, i;
ret = nvif_object_map(&chan->user, NULL, 0);
ret = nvif_object_map(chan->userd, NULL, 0);
if (ret)
return ret;
if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO &&
chan->user.oclass < AMPERE_CHANNEL_GPFIFO_B) {
ret = nvif_notify_ctor(&chan->user, "abi16ChanKilled",
nouveau_channel_killed,
true, NV906F_V0_NTFY_KILLED,
NULL, 0, 0, &chan->kill);
if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) {
struct {
struct nvif_event_v0 base;
struct nvif_chan_event_v0 host;
} args;
args.host.version = 0;
args.host.type = NVIF_CHAN_EVENT_V0_KILLED;
ret = nvif_event_ctor(&chan->user, "abi16ChanKilled", chan->chid,
nouveau_channel_killed, false,
&args.base, sizeof(args), &chan->kill);
if (ret == 0)
ret = nvif_notify_get(&chan->kill);
ret = nvif_event_allow(&chan->kill);
if (ret) {
NV_ERROR(drm, "Failed to request channel kill "
"notification: %d\n", ret);
@ -503,24 +486,18 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
int
nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
u32 arg0, u32 arg1, bool priv,
struct nouveau_channel **pchan)
bool priv, u64 runm, u32 vram, u32 gart, struct nouveau_channel **pchan)
{
struct nouveau_cli *cli = (void *)device->object.client;
int ret;
/* hack until fencenv50 is fixed, and agp access relaxed */
ret = nouveau_channel_ind(drm, device, arg0, priv, pchan);
ret = nouveau_channel_ctor(drm, device, priv, runm, pchan);
if (ret) {
NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret);
ret = nouveau_channel_dma(drm, device, pchan);
if (ret) {
NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret);
return ret;
}
NV_PRINTK(dbg, cli, "channel create, %d\n", ret);
return ret;
}
ret = nouveau_channel_init(*pchan, arg0, arg1);
ret = nouveau_channel_init(*pchan, vram, gart);
if (ret) {
NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret);
nouveau_channel_del(pchan);
@ -534,6 +511,12 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
return ret;
}
void
nouveau_channels_fini(struct nouveau_drm *drm)
{
kfree(drm->runl);
}
int
nouveau_channels_init(struct nouveau_drm *drm)
{
@ -541,20 +524,53 @@ nouveau_channels_init(struct nouveau_drm *drm)
struct nv_device_info_v1 m;
struct {
struct nv_device_info_v1_data channels;
struct nv_device_info_v1_data runlists;
} v;
} args = {
.m.version = 1,
.m.count = sizeof(args.v) / sizeof(args.v.channels),
.v.channels.mthd = NV_DEVICE_HOST_CHANNELS,
.v.runlists.mthd = NV_DEVICE_HOST_RUNLISTS,
};
struct nvif_object *device = &drm->client.device.object;
int ret;
int ret, i;
ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args));
if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
if (ret ||
args.v.runlists.mthd == NV_DEVICE_INFO_INVALID || !args.v.runlists.data ||
args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
return -ENODEV;
drm->chan.nr = args.v.channels.data;
drm->chan.context_base = dma_fence_context_alloc(drm->chan.nr);
drm->chan_nr = drm->chan_total = args.v.channels.data;
drm->runl_nr = fls64(args.v.runlists.data);
drm->runl = kcalloc(drm->runl_nr, sizeof(*drm->runl), GFP_KERNEL);
if (!drm->runl)
return -ENOMEM;
if (drm->chan_nr == 0) {
for (i = 0; i < drm->runl_nr; i++) {
if (!(args.v.runlists.data & BIT(i)))
continue;
args.v.channels.mthd = NV_DEVICE_HOST_RUNLIST_CHANNELS;
args.v.channels.data = i;
ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args));
if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
return -ENODEV;
drm->runl[i].chan_nr = args.v.channels.data;
drm->runl[i].chan_id_base = drm->chan_total;
drm->runl[i].context_base = dma_fence_context_alloc(drm->runl[i].chan_nr);
drm->chan_total += drm->runl[i].chan_nr;
}
} else {
drm->runl[0].context_base = dma_fence_context_alloc(drm->chan_nr);
for (i = 1; i < drm->runl_nr; i++)
drm->runl[i].context_base = drm->runl[0].context_base;
}
return 0;
}

View file

@ -2,7 +2,7 @@
#ifndef __NOUVEAU_CHAN_H__
#define __NOUVEAU_CHAN_H__
#include <nvif/object.h>
#include <nvif/notify.h>
#include <nvif/event.h>
#include <nvif/push.h>
struct nvif_device;
@ -16,6 +16,10 @@ struct nouveau_channel {
struct nouveau_drm *drm;
struct nouveau_vmm *vmm;
struct nvif_mem mem_userd;
struct nvif_object *userd;
int runlist;
int chid;
u64 inst;
u32 token;
@ -50,15 +54,15 @@ struct nouveau_channel {
struct nvif_object user;
struct nvif_notify kill;
struct nvif_event kill;
atomic_t killed;
};
int nouveau_channels_init(struct nouveau_drm *);
void nouveau_channels_fini(struct nouveau_drm *);
int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *,
u32 arg0, u32 arg1, bool priv,
struct nouveau_channel **);
int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *, bool priv, u64 runm,
u32 vram, u32 gart, struct nouveau_channel **);
void nouveau_channel_del(struct nouveau_channel **);
int nouveau_channel_idle(struct nouveau_channel *);

View file

@ -47,8 +47,7 @@
#include "nouveau_crtc.h"
#include <nvif/class.h>
#include <nvif/cl0046.h>
#include <nvif/event.h>
#include <nvif/if0011.h>
struct drm_display_mode *
nouveau_conn_native_mode(struct drm_connector *connector)
@ -396,7 +395,8 @@ static void
nouveau_connector_destroy(struct drm_connector *connector)
{
struct nouveau_connector *nv_connector = nouveau_connector(connector);
nvif_notify_dtor(&nv_connector->hpd);
nvif_event_dtor(&nv_connector->irq);
nvif_event_dtor(&nv_connector->hpd);
kfree(nv_connector->edid);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
@ -1162,39 +1162,38 @@ nouveau_connector_funcs_lvds = {
};
void
nouveau_connector_hpd(struct drm_connector *connector)
nouveau_connector_hpd(struct nouveau_connector *nv_connector, u64 bits)
{
struct nouveau_drm *drm = nouveau_drm(connector->dev);
u32 mask = drm_connector_mask(connector);
struct nouveau_drm *drm = nouveau_drm(nv_connector->base.dev);
u32 mask = drm_connector_mask(&nv_connector->base);
unsigned long flags;
mutex_lock(&drm->hpd_lock);
spin_lock_irqsave(&drm->hpd_lock, flags);
if (!(drm->hpd_pending & mask)) {
nv_connector->hpd_pending |= bits;
drm->hpd_pending |= mask;
schedule_work(&drm->hpd_work);
}
mutex_unlock(&drm->hpd_lock);
spin_unlock_irqrestore(&drm->hpd_lock, flags);
}
static int
nouveau_connector_hotplug(struct nvif_notify *notify)
nouveau_connector_irq(struct nvif_event *event, void *repv, u32 repc)
{
struct nouveau_connector *nv_connector =
container_of(notify, typeof(*nv_connector), hpd);
struct drm_connector *connector = &nv_connector->base;
struct drm_device *dev = connector->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
const struct nvif_notify_conn_rep_v0 *rep = notify->data;
bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), irq);
if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
nouveau_dp_irq(drm, nv_connector);
return NVIF_NOTIFY_KEEP;
}
schedule_work(&nv_connector->irq_work);
return NVIF_EVENT_KEEP;
}
NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", connector->name);
nouveau_connector_hpd(connector);
static int
nouveau_connector_hotplug(struct nvif_event *event, void *repv, u32 repc)
{
struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), hpd);
struct nvif_conn_event_v0 *rep = repv;
return NVIF_NOTIFY_KEEP;
nouveau_connector_hpd(nv_connector, rep->types);
return NVIF_EVENT_KEEP;
}
static ssize_t
@ -1290,6 +1289,7 @@ nouveau_connector_create(struct drm_device *dev,
connector = &nv_connector->base;
nv_connector->index = index;
INIT_WORK(&nv_connector->irq_work, nouveau_dp_irq);
/* attempt to parse vbios connector type and hotplug gpio */
nv_connector->dcb = olddcb_conn(dev, index);
@ -1401,6 +1401,7 @@ nouveau_connector_create(struct drm_device *dev,
drm_connector_init(dev, connector, funcs, type);
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) {
ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index,
@ -1409,6 +1410,25 @@ nouveau_connector_create(struct drm_device *dev,
kfree(nv_connector);
return ERR_PTR(ret);
}
ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug",
nouveau_connector_hotplug,
NVIF_CONN_EVENT_V0_PLUG | NVIF_CONN_EVENT_V0_UNPLUG,
&nv_connector->hpd);
if (ret == 0)
connector->polled = DRM_CONNECTOR_POLL_HPD;
if (nv_connector->aux.transfer) {
ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsDpIrq",
nouveau_connector_irq, NVIF_CONN_EVENT_V0_IRQ,
&nv_connector->irq);
if (ret) {
nvif_event_dtor(&nv_connector->hpd);
nvif_conn_dtor(&nv_connector->conn);
kfree(nv_connector);
return ERR_PTR(ret);
}
}
}
connector->funcs->reset(connector);
@ -1452,21 +1472,6 @@ nouveau_connector_create(struct drm_device *dev,
break;
}
ret = nvif_notify_ctor(&disp->disp.object, "kmsHotplug",
nouveau_connector_hotplug,
true, NV04_DISP_NTFY_CONN,
&(struct nvif_notify_conn_req_v0) {
.mask = NVIF_NOTIFY_CONN_V0_ANY,
.conn = index,
},
sizeof(struct nvif_notify_conn_req_v0),
sizeof(struct nvif_notify_conn_rep_v0),
&nv_connector->hpd);
if (ret)
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
else
connector->polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_register(connector);
return connector;
}

View file

@ -27,7 +27,7 @@
#ifndef __NOUVEAU_CONNECTOR_H__
#define __NOUVEAU_CONNECTOR_H__
#include <nvif/conn.h>
#include <nvif/notify.h>
#include <nvif/event.h>
#include <nvhw/class/cl507d.h>
#include <nvhw/class/cl907d.h>
@ -124,7 +124,10 @@ struct nouveau_connector {
u8 *dcb;
struct nvif_conn conn;
struct nvif_notify hpd;
u64 hpd_pending;
struct nvif_event hpd;
struct nvif_event irq;
struct work_struct irq_work;
struct drm_dp_aux aux;
@ -198,7 +201,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
struct drm_connector *
nouveau_connector_create(struct drm_device *, const struct dcb_output *);
void nouveau_connector_hpd(struct drm_connector *connector);
void nouveau_connector_hpd(struct nouveau_connector *, u64 bits);
extern int nouveau_tv_disable;
extern int nouveau_ignorelid;

View file

@ -26,16 +26,17 @@
#ifndef __NOUVEAU_CRTC_H__
#define __NOUVEAU_CRTC_H__
#include <drm/drm_crtc.h>
#include <nvif/notify.h>
#include <nvif/head.h>
#include <nvif/event.h>
struct nouveau_crtc {
struct drm_crtc base;
struct nvif_head head;
int index;
struct nvif_notify vblank;
struct nvif_event vblank;
uint32_t dpms_saved_fp_control;
uint32_t fp_users;

View file

@ -35,15 +35,14 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "nouveau_fbcon.h"
#include "nouveau_crtc.h"
#include "nouveau_gem.h"
#include "nouveau_connector.h"
#include "nv50_display.h"
#include <nvif/class.h>
#include <nvif/cl0046.h>
#include <nvif/event.h>
#include <nvif/if0011.h>
#include <nvif/if0013.h>
#include <dispnv50/crc.h>
int
@ -52,7 +51,7 @@ nouveau_display_vblank_enable(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc;
nv_crtc = nouveau_crtc(crtc);
nvif_notify_get(&nv_crtc->vblank);
nvif_event_allow(&nv_crtc->vblank);
return 0;
}
@ -63,7 +62,7 @@ nouveau_display_vblank_disable(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc;
nv_crtc = nouveau_crtc(crtc);
nvif_notify_put(&nv_crtc->vblank);
nvif_event_block(&nv_crtc->vblank);
}
static inline int
@ -84,24 +83,20 @@ static bool
nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime)
{
struct {
struct nv04_disp_mthd_v0 base;
struct nv04_disp_scanoutpos_v0 scan;
} args = {
.base.method = NV04_DISP_SCANOUTPOS,
.base.head = nouveau_crtc(crtc)->index,
};
struct nouveau_display *disp = nouveau_display(crtc->dev);
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
struct nvif_head *head = &nouveau_crtc(crtc)->head;
struct nvif_head_scanoutpos_v0 args;
int retry = 20;
bool ret = false;
args.version = 0;
do {
ret = nvif_mthd(&disp->disp.object, 0, &args, sizeof(args));
ret = nvif_mthd(&head->object, NVIF_HEAD_V0_SCANOUTPOS, &args, sizeof(args));
if (ret != 0)
return false;
if (args.scan.vline) {
if (args.vline) {
ret = true;
break;
}
@ -109,11 +104,10 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
if (retry) ndelay(vblank->linedur_ns);
} while (retry--);
*hpos = args.scan.hline;
*vpos = calc(args.scan.vblanks, args.scan.vblanke,
args.scan.vtotal, args.scan.vline);
if (stime) *stime = ns_to_ktime(args.scan.time[0]);
if (etime) *etime = ns_to_ktime(args.scan.time[1]);
*hpos = args.hline;
*vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline);
if (stime) *stime = ns_to_ktime(args.time[0]);
if (etime) *etime = ns_to_ktime(args.time[1]);
return ret;
}
@ -397,7 +391,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
.fb_create = nouveau_user_framebuffer_create,
.output_poll_changed = nouveau_fbcon_output_poll_changed,
.output_poll_changed = drm_fb_helper_output_poll_changed,
};
@ -456,9 +450,9 @@ nouveau_display_hpd_resume(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
mutex_lock(&drm->hpd_lock);
spin_lock_irq(&drm->hpd_lock);
drm->hpd_pending = ~0;
mutex_unlock(&drm->hpd_lock);
spin_unlock_irq(&drm->hpd_lock);
schedule_work(&drm->hpd_work);
}
@ -475,10 +469,10 @@ nouveau_display_hpd_work(struct work_struct *work)
pm_runtime_get_sync(dev->dev);
mutex_lock(&drm->hpd_lock);
spin_lock_irq(&drm->hpd_lock);
pending = drm->hpd_pending;
drm->hpd_pending = 0;
mutex_unlock(&drm->hpd_lock);
spin_unlock_irq(&drm->hpd_lock);
/* Nothing to do, exit early without updating the last busy counter */
if (!pending)
@ -488,14 +482,30 @@ nouveau_display_hpd_work(struct work_struct *work)
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *nv_connector = nouveau_connector(connector);
enum drm_connector_status old_status = connector->status;
u64 old_epoch_counter = connector->epoch_counter;
u64 bits, old_epoch_counter = connector->epoch_counter;
if (!(pending & drm_connector_mask(connector)))
continue;
connector->status = drm_helper_probe_detect(connector, NULL,
false);
spin_lock_irq(&drm->hpd_lock);
bits = nv_connector->hpd_pending;
nv_connector->hpd_pending = 0;
spin_unlock_irq(&drm->hpd_lock);
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] plug:%d unplug:%d irq:%d\n",
connector->base.id, connector->name,
!!(bits & NVIF_CONN_EVENT_V0_PLUG),
!!(bits & NVIF_CONN_EVENT_V0_UNPLUG),
!!(bits & NVIF_CONN_EVENT_V0_IRQ));
if (bits & NVIF_CONN_EVENT_V0_IRQ) {
if (nouveau_dp_link_check(nv_connector))
continue;
}
connector->status = drm_helper_probe_detect(connector, NULL, false);
if (old_epoch_counter == connector->epoch_counter)
continue;
@ -573,7 +583,8 @@ nouveau_display_init(struct drm_device *dev, bool resume, bool runtime)
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector);
nvif_notify_get(&conn->hpd);
nvif_event_allow(&conn->hpd);
nvif_event_allow(&conn->irq);
}
drm_connector_list_iter_end(&conn_iter);
@ -608,7 +619,8 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector);
nvif_notify_put(&conn->hpd);
nvif_event_block(&conn->irq);
nvif_event_block(&conn->hpd);
}
drm_connector_list_iter_end(&conn_iter);
@ -732,7 +744,7 @@ nouveau_display_create(struct drm_device *dev)
}
INIT_WORK(&drm->hpd_work, nouveau_display_hpd_work);
mutex_init(&drm->hpd_lock);
spin_lock_init(&drm->hpd_lock);
#ifdef CONFIG_ACPI
drm->acpi_nb.notifier_call = nouveau_display_acpi_ntfy;
register_acpi_notifier(&drm->acpi_nb);
@ -766,8 +778,7 @@ nouveau_display_destroy(struct drm_device *dev)
nvif_disp_dtor(&disp->disp);
nouveau_drm(dev)->display = NULL;
mutex_destroy(&drm->hpd_lock);
drm->display = NULL;
kfree(disp);
}
@ -776,6 +787,9 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
{
struct nouveau_display *disp = nouveau_display(dev);
/* Disable console. */
drm_fb_helper_set_suspend_unlocked(dev->fb_helper, true);
if (drm_drv_uses_atomic_modeset(dev)) {
if (!runtime) {
disp->suspend = drm_atomic_helper_suspend(dev);
@ -803,8 +817,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
drm_atomic_helper_resume(dev, disp->suspend);
disp->suspend = NULL;
}
return;
}
/* Enable console. */
drm_fb_helper_set_suspend_unlocked(dev->fb_helper, false);
}
int

View file

@ -42,9 +42,9 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout)
{
uint64_t val;
val = nvif_rd32(&chan->user, chan->user_get);
val = nvif_rd32(chan->userd, chan->user_get);
if (chan->user_get_hi)
val |= (uint64_t)nvif_rd32(&chan->user, chan->user_get_hi) << 32;
val |= (uint64_t)nvif_rd32(chan->userd, chan->user_get_hi) << 32;
/* reset counter as long as GET is still advancing, this is
* to avoid misdetecting a GPU lockup if the GPU happens to
@ -86,7 +86,7 @@ nv50_dma_push(struct nouveau_channel *chan, u64 offset, int length)
/* Flush writes. */
nouveau_bo_rd32(pb, 0);
nvif_wr32(&chan->user, 0x8c, chan->dma.ib_put);
nvif_wr32(chan->userd, 0x8c, chan->dma.ib_put);
if (user->func && user->func->doorbell)
user->func->doorbell(user, chan->token);
chan->dma.ib_free--;
@ -98,7 +98,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count)
uint32_t cnt = 0, prev_get = 0;
while (chan->dma.ib_free < count) {
uint32_t get = nvif_rd32(&chan->user, 0x88);
uint32_t get = nvif_rd32(chan->userd, 0x88);
if (get != prev_get) {
prev_get = get;
cnt = 0;

View file

@ -29,8 +29,7 @@
#include "nouveau_encoder.h"
#include "nouveau_crtc.h"
#include <nvif/class.h>
#include <nvif/cl5070.h>
#include <nvif/if0011.h>
MODULE_PARM_DESC(mst, "Enable DisplayPort multi-stream (default: enabled)");
static int nouveau_mst = 1;
@ -140,12 +139,17 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
* TODO: look into checking this before probing I2C to detect DVI/HDMI
*/
hpd = nvif_conn_hpd_status(&nv_connector->conn);
if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT)
if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT) {
nvif_outp_dp_aux_pwr(&nv_encoder->outp, false);
goto out;
}
nvif_outp_dp_aux_pwr(&nv_encoder->outp, true);
status = nouveau_dp_probe_dpcd(nv_connector, nv_encoder);
if (status == connector_status_disconnected)
if (status == connector_status_disconnected) {
nvif_outp_dp_aux_pwr(&nv_encoder->outp, false);
goto out;
}
/* If we're in MST mode, we're done here */
if (mstm && mstm->can_mst && mstm->is_mst) {
@ -193,6 +197,7 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
ret = NOUVEAU_DP_MST;
goto out;
} else if (ret != 0) {
nvif_outp_dp_aux_pwr(&nv_encoder->outp, false);
goto out;
}
}
@ -206,14 +211,28 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
return ret;
}
void nouveau_dp_irq(struct nouveau_drm *drm,
struct nouveau_connector *nv_connector)
bool
nouveau_dp_link_check(struct nouveau_connector *nv_connector)
{
struct nouveau_encoder *nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
if (!nv_encoder || nv_encoder->outp.or.id < 0)
return true;
return nvif_outp_dp_retrain(&nv_encoder->outp) == 0;
}
void
nouveau_dp_irq(struct work_struct *work)
{
struct nouveau_connector *nv_connector =
container_of(work, typeof(*nv_connector), irq_work);
struct drm_connector *connector = &nv_connector->base;
struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP);
struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev);
struct nv50_mstm *mstm;
u64 hpd = 0;
int ret;
bool send_hpd = false;
if (!outp)
return;
@ -225,14 +244,14 @@ void nouveau_dp_irq(struct nouveau_drm *drm,
if (mstm && mstm->is_mst) {
if (!nv50_mstm_service(drm, nv_connector, mstm))
send_hpd = true;
hpd |= NVIF_CONN_EVENT_V0_UNPLUG;
} else {
drm_dp_cec_irq(&nv_connector->aux);
if (nouveau_dp_has_sink_count(connector, outp)) {
ret = drm_dp_read_sink_count(&nv_connector->aux);
if (ret != outp->dp.sink_count)
send_hpd = true;
hpd |= NVIF_CONN_EVENT_V0_PLUG;
if (ret >= 0)
outp->dp.sink_count = ret;
}
@ -240,8 +259,7 @@ void nouveau_dp_irq(struct nouveau_drm *drm,
mutex_unlock(&outp->dp.hpd_irq_lock);
if (send_hpd)
nouveau_connector_hpd(connector);
nouveau_connector_hpd(nv_connector, NVIF_CONN_EVENT_V0_IRQ | hpd);
}
/* TODO:

View file

@ -33,6 +33,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_vblank.h>
@ -49,7 +50,6 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
#include <nvif/cla06f.h>
#include "nouveau_drv.h"
#include "nouveau_dma.h"
@ -62,7 +62,6 @@
#include "nouveau_bios.h"
#include "nouveau_ioctl.h"
#include "nouveau_abi16.h"
#include "nouveau_fbcon.h"
#include "nouveau_fence.h"
#include "nouveau_debugfs.h"
#include "nouveau_usif.h"
@ -316,28 +315,19 @@ static void
nouveau_accel_ce_init(struct nouveau_drm *drm)
{
struct nvif_device *device = &drm->client.device;
u64 runm;
int ret = 0;
/* Allocate channel that has access to a (preferably async) copy
* engine, to use for TTM buffer moves.
*/
if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
ret = nouveau_channel_new(drm, device,
nvif_fifo_runlist_ce(device), 0,
true, &drm->cechan);
} else
if (device->info.chipset >= 0xa3 &&
device->info.chipset != 0xaa &&
device->info.chipset != 0xac) {
/* Prior to Kepler, there's only a single runlist, so all
* engines can be accessed from any channel.
*
* We still want to use a separate channel though.
*/
ret = nouveau_channel_new(drm, device, NvDmaFB, NvDmaTT, false,
&drm->cechan);
runm = nvif_fifo_runlist_ce(device);
if (!runm) {
NV_DEBUG(drm, "no ce runlist\n");
return;
}
ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->cechan);
if (ret)
NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
}
@ -355,23 +345,17 @@ static void
nouveau_accel_gr_init(struct nouveau_drm *drm)
{
struct nvif_device *device = &drm->client.device;
u32 arg0, arg1;
u64 runm;
int ret;
if (device->info.family >= NV_DEVICE_INFO_V0_AMPERE)
return;
/* Allocate channel that has access to the graphics engine. */
if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
arg0 = nvif_fifo_runlist(device, NV_DEVICE_HOST_RUNLIST_ENGINES_GR);
arg1 = 1;
} else {
arg0 = NvDmaFB;
arg1 = NvDmaTT;
runm = nvif_fifo_runlist(device, NV_DEVICE_HOST_RUNLIST_ENGINES_GR);
if (!runm) {
NV_DEBUG(drm, "no gr runlist\n");
return;
}
ret = nouveau_channel_new(drm, device, arg0, arg1, false,
&drm->channel);
ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->channel);
if (ret) {
NV_ERROR(drm, "failed to create kernel channel, %d\n", ret);
nouveau_accel_gr_fini(drm);
@ -436,6 +420,7 @@ nouveau_accel_fini(struct nouveau_drm *drm)
nouveau_accel_gr_fini(drm);
if (drm->fence)
nouveau_fence(drm)->dtor(drm);
nouveau_channels_fini(drm);
}
static void
@ -485,6 +470,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
case PASCAL_CHANNEL_GPFIFO_A:
case VOLTA_CHANNEL_GPFIFO_A:
case TURING_CHANNEL_GPFIFO_A:
case AMPERE_CHANNEL_GPFIFO_A:
case AMPERE_CHANNEL_GPFIFO_B:
ret = nvc0_fence_create(drm);
break;
@ -611,7 +597,6 @@ nouveau_drm_device_init(struct drm_device *dev)
nouveau_hwmon_init(dev);
nouveau_svm_init(drm);
nouveau_dmem_init(drm);
nouveau_fbcon_init(dev);
nouveau_led_init(dev);
if (nouveau_pmops_runtime()) {
@ -655,7 +640,6 @@ nouveau_drm_device_fini(struct drm_device *dev)
}
nouveau_led_fini(dev);
nouveau_fbcon_fini(dev);
nouveau_dmem_fini(drm);
nouveau_svm_fini(drm);
nouveau_hwmon_fini(dev);
@ -809,6 +793,11 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
if (ret)
goto fail_drm_dev_init;
if (nouveau_drm(drm_dev)->client.device.info.ram_size <= 32 * 1024 * 1024)
drm_fbdev_generic_setup(drm_dev, 8);
else
drm_fbdev_generic_setup(drm_dev, 32);
quirk_broken_nv_runpm(pdev);
return 0;
@ -865,8 +854,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
nouveau_led_suspend(dev);
if (dev->mode_config.num_crtc) {
NV_DEBUG(drm, "suspending console...\n");
nouveau_fbcon_set_suspend(dev, 1);
NV_DEBUG(drm, "suspending display...\n");
ret = nouveau_display_suspend(dev, runtime);
if (ret)
@ -940,8 +927,6 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
if (dev->mode_config.num_crtc) {
NV_DEBUG(drm, "resuming display...\n");
nouveau_display_resume(dev, runtime);
NV_DEBUG(drm, "resuming console...\n");
nouveau_fbcon_set_suspend(dev, 0);
}
nouveau_led_resume(dev);
@ -1296,7 +1281,6 @@ static void nouveau_display_options(void)
DRM_DEBUG_DRIVER("... tv_disable : %d\n", nouveau_tv_disable);
DRM_DEBUG_DRIVER("... ignorelid : %d\n", nouveau_ignorelid);
DRM_DEBUG_DRIVER("... duallink : %d\n", nouveau_duallink);
DRM_DEBUG_DRIVER("... nofbaccel : %d\n", nouveau_nofbaccel);
DRM_DEBUG_DRIVER("... config : %s\n", nouveau_config);
DRM_DEBUG_DRIVER("... debug : %s\n", nouveau_debug);
DRM_DEBUG_DRIVER("... noaccel : %d\n", nouveau_noaccel);

View file

@ -78,11 +78,6 @@ enum nouveau_drm_object_route {
NVDRM_OBJECT_ANY = NVIF_IOCTL_V0_OWNER_ANY,
};
enum nouveau_drm_notify_route {
NVDRM_NOTIFY_NVIF = 0,
NVDRM_NOTIFY_USIF
};
enum nouveau_drm_handle {
NVDRM_CHAN = 0xcccc0000, /* |= client chid */
NVDRM_NVSW = 0x55550000,
@ -179,16 +174,19 @@ struct nouveau_drm {
void *fence;
/* Global channel management. */
int chan_total; /* Number of channels across all runlists. */
int chan_nr; /* 0 if per-runlist CHIDs. */
int runl_nr;
struct {
int nr;
int chan_nr;
int chan_id_base;
u64 context_base;
} chan;
} *runl;
/* context for accelerated drm-internal operations */
struct nouveau_channel *cechan;
struct nouveau_channel *channel;
struct nvkm_gpuobj *notify;
struct nouveau_fbdev *fbcon;
struct nvif_object ntfy;
/* nv10-nv40 tiling regions */
@ -201,10 +199,8 @@ struct nouveau_drm {
struct nvbios vbios;
struct nouveau_display *display;
struct work_struct hpd_work;
struct mutex hpd_lock;
spinlock_t hpd_lock;
u32 hpd_pending;
struct work_struct fbcon_work;
int fbcon_new_state;
#ifdef CONFIG_ACPI
struct notifier_block acpi_nb;
#endif

View file

@ -48,7 +48,6 @@ struct nouveau_encoder {
struct dcb_output *dcb;
struct nvif_outp outp;
int or;
int link;
struct i2c_adapter *i2c;
struct nvkm_i2c_aux *aux;
@ -142,8 +141,8 @@ enum nouveau_dp_status {
};
int nouveau_dp_detect(struct nouveau_connector *, struct nouveau_encoder *);
void nouveau_dp_irq(struct nouveau_drm *drm,
struct nouveau_connector *nv_connector);
bool nouveau_dp_link_check(struct nouveau_connector *);
void nouveau_dp_irq(struct work_struct *);
enum drm_mode_status nv50_dp_mode_valid(struct drm_connector *,
struct nouveau_encoder *,
const struct drm_display_mode *,

View file

@ -1,614 +0,0 @@
/*
* Copyright © 2007 David Airlie
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* David Airlie
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/screen_info.h>
#include <linux/vga_switcheroo.h>
#include <linux/console.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_atomic.h>
#include "nouveau_drv.h"
#include "nouveau_gem.h"
#include "nouveau_bo.h"
#include "nouveau_fbcon.h"
#include "nouveau_chan.h"
#include "nouveau_vmm.h"
#include "nouveau_crtc.h"
MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
int nouveau_nofbaccel = 0;
module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
MODULE_PARM_DESC(fbcon_bpp, "fbcon bits-per-pixel (default: auto)");
static int nouveau_fbcon_bpp;
module_param_named(fbcon_bpp, nouveau_fbcon_bpp, int, 0400);
static void
nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *fbcon = info->par;
struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
struct nvif_device *device = &drm->client.device;
int ret;
if (info->state != FBINFO_STATE_RUNNING)
return;
ret = -ENODEV;
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
mutex_trylock(&drm->client.mutex)) {
if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
ret = nv04_fbcon_fillrect(info, rect);
else
if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
ret = nv50_fbcon_fillrect(info, rect);
else
ret = nvc0_fbcon_fillrect(info, rect);
mutex_unlock(&drm->client.mutex);
}
if (ret == 0)
return;
if (ret != -ENODEV)
nouveau_fbcon_gpu_lockup(info);
drm_fb_helper_cfb_fillrect(info, rect);
}
static void
nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
{
struct nouveau_fbdev *fbcon = info->par;
struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
struct nvif_device *device = &drm->client.device;
int ret;
if (info->state != FBINFO_STATE_RUNNING)
return;
ret = -ENODEV;
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
mutex_trylock(&drm->client.mutex)) {
if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
ret = nv04_fbcon_copyarea(info, image);
else
if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
ret = nv50_fbcon_copyarea(info, image);
else
ret = nvc0_fbcon_copyarea(info, image);
mutex_unlock(&drm->client.mutex);
}
if (ret == 0)
return;
if (ret != -ENODEV)
nouveau_fbcon_gpu_lockup(info);
drm_fb_helper_cfb_copyarea(info, image);
}
static void
nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *fbcon = info->par;
struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
struct nvif_device *device = &drm->client.device;
int ret;
if (info->state != FBINFO_STATE_RUNNING)
return;
ret = -ENODEV;
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
mutex_trylock(&drm->client.mutex)) {
if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
ret = nv04_fbcon_imageblit(info, image);
else
if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
ret = nv50_fbcon_imageblit(info, image);
else
ret = nvc0_fbcon_imageblit(info, image);
mutex_unlock(&drm->client.mutex);
}
if (ret == 0)
return;
if (ret != -ENODEV)
nouveau_fbcon_gpu_lockup(info);
drm_fb_helper_cfb_imageblit(info, image);
}
static int
nouveau_fbcon_sync(struct fb_info *info)
{
struct nouveau_fbdev *fbcon = info->par;
struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
struct nouveau_channel *chan = drm->channel;
int ret;
if (!chan || !chan->accel_done || in_interrupt() ||
info->state != FBINFO_STATE_RUNNING ||
info->flags & FBINFO_HWACCEL_DISABLED)
return 0;
if (!mutex_trylock(&drm->client.mutex))
return 0;
ret = nouveau_channel_idle(chan);
mutex_unlock(&drm->client.mutex);
if (ret) {
nouveau_fbcon_gpu_lockup(info);
return 0;
}
chan->accel_done = false;
return 0;
}
static int
nouveau_fbcon_open(struct fb_info *info, int user)
{
struct nouveau_fbdev *fbcon = info->par;
struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
int ret = pm_runtime_get_sync(drm->dev->dev);
if (ret < 0 && ret != -EACCES) {
pm_runtime_put(drm->dev->dev);
return ret;
}
return 0;
}
static int
nouveau_fbcon_release(struct fb_info *info, int user)
{
struct nouveau_fbdev *fbcon = info->par;
struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
pm_runtime_put(drm->dev->dev);
return 0;
}
static const struct fb_ops nouveau_fbcon_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
.fb_open = nouveau_fbcon_open,
.fb_release = nouveau_fbcon_release,
.fb_fillrect = nouveau_fbcon_fillrect,
.fb_copyarea = nouveau_fbcon_copyarea,
.fb_imageblit = nouveau_fbcon_imageblit,
.fb_sync = nouveau_fbcon_sync,
};
static const struct fb_ops nouveau_fbcon_sw_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
.fb_open = nouveau_fbcon_open,
.fb_release = nouveau_fbcon_release,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
};
void
nouveau_fbcon_accel_save_disable(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (drm->fbcon && drm->fbcon->helper.fbdev) {
drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
}
}
void
nouveau_fbcon_accel_restore(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (drm->fbcon && drm->fbcon->helper.fbdev) {
drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
}
}
static void
nouveau_fbcon_accel_fini(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_fbdev *fbcon = drm->fbcon;
if (fbcon && drm->channel) {
console_lock();
if (fbcon->helper.fbdev)
fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
console_unlock();
nouveau_channel_idle(drm->channel);
nvif_object_dtor(&fbcon->twod);
nvif_object_dtor(&fbcon->blit);
nvif_object_dtor(&fbcon->gdi);
nvif_object_dtor(&fbcon->patt);
nvif_object_dtor(&fbcon->rop);
nvif_object_dtor(&fbcon->clip);
nvif_object_dtor(&fbcon->surf2d);
}
}
static void
nouveau_fbcon_accel_init(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_fbdev *fbcon = drm->fbcon;
struct fb_info *info = fbcon->helper.fbdev;
int ret;
if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA)
ret = nv04_fbcon_accel_init(info);
else
if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI)
ret = nv50_fbcon_accel_init(info);
else
ret = nvc0_fbcon_accel_init(info);
if (ret == 0)
info->fbops = &nouveau_fbcon_ops;
}
static void
nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
{
struct fb_info *info = fbcon->helper.fbdev;
struct fb_fillrect rect;
/* Clear the entire fbcon. The drm will program every connector
* with it's preferred mode. If the sizes differ, one display will
* quite likely have garbage around the console.
*/
rect.dx = rect.dy = 0;
rect.width = info->var.xres_virtual;
rect.height = info->var.yres_virtual;
rect.color = 0;
rect.rop = ROP_COPY;
info->fbops->fb_fillrect(info, &rect);
}
static int
nouveau_fbcon_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct nouveau_fbdev *fbcon =
container_of(helper, struct nouveau_fbdev, helper);
struct drm_device *dev = fbcon->helper.dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &drm->client.device;
struct fb_info *info;
struct drm_framebuffer *fb;
struct nouveau_channel *chan;
struct nouveau_bo *nvbo;
struct drm_mode_fb_cmd2 mode_cmd = {};
int ret;
mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;
mode_cmd.pitches[0] = mode_cmd.width * (sizes->surface_bpp >> 3);
mode_cmd.pitches[0] = roundup(mode_cmd.pitches[0], 256);
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth);
ret = nouveau_gem_new(&drm->client, mode_cmd.pitches[0] *
mode_cmd.height, 0, NOUVEAU_GEM_DOMAIN_VRAM,
0, 0x0000, &nvbo);
if (ret) {
NV_ERROR(drm, "failed to allocate framebuffer\n");
goto out;
}
ret = nouveau_framebuffer_new(dev, &mode_cmd, &nvbo->bo.base, &fb);
if (ret)
goto out_unref;
ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
if (ret) {
NV_ERROR(drm, "failed to pin fb: %d\n", ret);
goto out_unref;
}
ret = nouveau_bo_map(nvbo);
if (ret) {
NV_ERROR(drm, "failed to map fb: %d\n", ret);
goto out_unpin;
}
chan = nouveau_nofbaccel ? NULL : drm->channel;
if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
ret = nouveau_vma_new(nvbo, chan->vmm, &fbcon->vma);
if (ret) {
NV_ERROR(drm, "failed to map fb into chan: %d\n", ret);
chan = NULL;
}
}
info = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(info)) {
ret = PTR_ERR(info);
goto out_unlock;
}
/* setup helper */
fbcon->helper.fb = fb;
if (!chan)
info->flags = FBINFO_HWACCEL_DISABLED;
else
info->flags = FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT;
info->fbops = &nouveau_fbcon_sw_ops;
info->fix.smem_start = nvbo->bo.resource->bus.offset;
info->fix.smem_len = nvbo->bo.base.size;
info->screen_base = nvbo_kmap_obj_iovirtual(nvbo);
info->screen_size = nvbo->bo.base.size;
drm_fb_helper_fill_info(info, &fbcon->helper, sizes);
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
if (chan)
nouveau_fbcon_accel_init(dev);
nouveau_fbcon_zfill(dev, fbcon);
/* To allow resizeing without swapping buffers */
NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n",
fb->width, fb->height, nvbo->offset, nvbo);
if (dev_is_pci(dev->dev))
vga_switcheroo_client_fb_set(to_pci_dev(dev->dev), info);
return 0;
out_unlock:
if (chan)
nouveau_vma_del(&fbcon->vma);
nouveau_bo_unmap(nvbo);
out_unpin:
nouveau_bo_unpin(nvbo);
out_unref:
nouveau_bo_ref(NULL, &nvbo);
out:
return ret;
}
static int
nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
{
struct drm_framebuffer *fb = fbcon->helper.fb;
struct nouveau_bo *nvbo;
drm_fb_helper_unregister_fbi(&fbcon->helper);
drm_fb_helper_fini(&fbcon->helper);
if (fb && fb->obj[0]) {
nvbo = nouveau_gem_object(fb->obj[0]);
nouveau_vma_del(&fbcon->vma);
nouveau_bo_unmap(nvbo);
nouveau_bo_unpin(nvbo);
drm_framebuffer_put(fb);
}
return 0;
}
void nouveau_fbcon_gpu_lockup(struct fb_info *info)
{
struct nouveau_fbdev *fbcon = info->par;
struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
NV_ERROR(drm, "GPU lockup - switching to software fbcon\n");
info->flags |= FBINFO_HWACCEL_DISABLED;
}
static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
.fb_probe = nouveau_fbcon_create,
};
static void
nouveau_fbcon_set_suspend_work(struct work_struct *work)
{
struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work);
int state = READ_ONCE(drm->fbcon_new_state);
if (state == FBINFO_STATE_RUNNING)
pm_runtime_get_sync(drm->dev->dev);
console_lock();
if (state == FBINFO_STATE_RUNNING)
nouveau_fbcon_accel_restore(drm->dev);
drm_fb_helper_set_suspend(&drm->fbcon->helper, state);
if (state != FBINFO_STATE_RUNNING)
nouveau_fbcon_accel_save_disable(drm->dev);
console_unlock();
if (state == FBINFO_STATE_RUNNING) {
nouveau_fbcon_hotplug_resume(drm->fbcon);
pm_runtime_mark_last_busy(drm->dev->dev);
pm_runtime_put_autosuspend(drm->dev->dev);
}
}
void
nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (!drm->fbcon)
return;
drm->fbcon_new_state = state;
/* Since runtime resume can happen as a result of a sysfs operation,
* it's possible we already have the console locked. So handle fbcon
* init/deinit from a seperate work thread
*/
schedule_work(&drm->fbcon_work);
}
void
nouveau_fbcon_output_poll_changed(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_fbdev *fbcon = drm->fbcon;
int ret;
if (!fbcon)
return;
mutex_lock(&fbcon->hotplug_lock);
ret = pm_runtime_get(dev->dev);
if (ret == 1 || ret == -EACCES) {
drm_fb_helper_hotplug_event(&fbcon->helper);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
} else if (ret == 0) {
/* If the GPU was already in the process of suspending before
* this event happened, then we can't block here as we'll
* deadlock the runtime pmops since they wait for us to
* finish. So, just defer this event for when we runtime
* resume again. It will be handled by fbcon_work.
*/
NV_DEBUG(drm, "fbcon HPD event deferred until runtime resume\n");
fbcon->hotplug_waiting = true;
pm_runtime_put_noidle(drm->dev->dev);
} else {
DRM_WARN("fbcon HPD event lost due to RPM failure: %d\n",
ret);
}
mutex_unlock(&fbcon->hotplug_lock);
}
void
nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon)
{
struct nouveau_drm *drm;
if (!fbcon)
return;
drm = nouveau_drm(fbcon->helper.dev);
mutex_lock(&fbcon->hotplug_lock);
if (fbcon->hotplug_waiting) {
fbcon->hotplug_waiting = false;
NV_DEBUG(drm, "Handling deferred fbcon HPD events\n");
drm_fb_helper_hotplug_event(&fbcon->helper);
}
mutex_unlock(&fbcon->hotplug_lock);
}
int
nouveau_fbcon_init(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_fbdev *fbcon;
int preferred_bpp = nouveau_fbcon_bpp;
int ret;
if (!dev->mode_config.num_crtc ||
(to_pci_dev(dev->dev)->class >> 8) != PCI_CLASS_DISPLAY_VGA)
return 0;
fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
if (!fbcon)
return -ENOMEM;
drm->fbcon = fbcon;
INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work);
mutex_init(&fbcon->hotplug_lock);
drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs);
ret = drm_fb_helper_init(dev, &fbcon->helper);
if (ret)
goto free;
if (preferred_bpp != 8 && preferred_bpp != 16 && preferred_bpp != 32) {
if (drm->client.device.info.ram_size <= 32 * 1024 * 1024)
preferred_bpp = 8;
else
if (drm->client.device.info.ram_size <= 64 * 1024 * 1024)
preferred_bpp = 16;
else
preferred_bpp = 32;
}
/* disable all the possible outputs/crtcs before entering KMS mode */
if (!drm_drv_uses_atomic_modeset(dev))
drm_helper_disable_unused_functions(dev);
ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
if (ret)
goto fini;
if (fbcon->helper.fbdev)
fbcon->helper.fbdev->pixmap.buf_align = 4;
return 0;
fini:
drm_fb_helper_fini(&fbcon->helper);
free:
kfree(fbcon);
drm->fbcon = NULL;
return ret;
}
void
nouveau_fbcon_fini(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (!drm->fbcon)
return;
drm_kms_helper_poll_fini(dev);
nouveau_fbcon_accel_fini(dev);
nouveau_fbcon_destroy(dev, drm->fbcon);
kfree(drm->fbcon);
drm->fbcon = NULL;
}

View file

@ -1,82 +0,0 @@
/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __NOUVEAU_FBCON_H__
#define __NOUVEAU_FBCON_H__
#include <drm/drm_fb_helper.h>
#include "nouveau_display.h"
struct nouveau_vma;
struct nouveau_fbdev {
struct drm_fb_helper helper; /* must be first */
unsigned int saved_flags;
struct nvif_object surf2d;
struct nvif_object clip;
struct nvif_object rop;
struct nvif_object patt;
struct nvif_object gdi;
struct nvif_object blit;
struct nvif_object twod;
struct nouveau_vma *vma;
struct mutex hotplug_lock;
bool hotplug_waiting;
};
void nouveau_fbcon_restore(void);
int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv04_fbcon_accel_init(struct fb_info *info);
int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv50_fbcon_accel_init(struct fb_info *info);
int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nvc0_fbcon_accel_init(struct fb_info *info);
void nouveau_fbcon_gpu_lockup(struct fb_info *info);
int nouveau_fbcon_init(struct drm_device *dev);
void nouveau_fbcon_fini(struct drm_device *dev);
void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
void nouveau_fbcon_accel_restore(struct drm_device *dev);
void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
void nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon);
extern int nouveau_nofbaccel;
#endif /* __NV50_FBCON_H__ */

View file

@ -29,9 +29,7 @@
#include <linux/sched/signal.h>
#include <trace/events/dma_fence.h>
#include <nvif/cl826e.h>
#include <nvif/notify.h>
#include <nvif/event.h>
#include <nvif/if0020.h>
#include "nouveau_drv.h"
#include "nouveau_dma.h"
@ -79,10 +77,6 @@ nouveau_local_fence(struct dma_fence *fence, struct nouveau_drm *drm)
fence->ops != &nouveau_fence_ops_uevent)
return NULL;
if (fence->context < drm->chan.context_base ||
fence->context >= drm->chan.context_base + drm->chan.nr)
return NULL;
return from_fence(fence);
}
@ -90,8 +84,9 @@ void
nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error)
{
struct nouveau_fence *fence;
unsigned long flags;
spin_lock_irq(&fctx->lock);
spin_lock_irqsave(&fctx->lock, flags);
while (!list_empty(&fctx->pending)) {
fence = list_entry(fctx->pending.next, typeof(*fence), head);
@ -99,16 +94,16 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error)
dma_fence_set_error(&fence->base, error);
if (nouveau_fence_signal(fence))
nvif_notify_put(&fctx->notify);
nvif_event_block(&fctx->event);
}
spin_unlock_irq(&fctx->lock);
spin_unlock_irqrestore(&fctx->lock, flags);
}
void
nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
{
nouveau_fence_context_kill(fctx, 0);
nvif_notify_dtor(&fctx->notify);
nvif_event_dtor(&fctx->event);
fctx->dead = 1;
/*
@ -150,12 +145,11 @@ nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fc
}
static int
nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc)
{
struct nouveau_fence_chan *fctx =
container_of(notify, typeof(*fctx), notify);
struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event);
unsigned long flags;
int ret = NVIF_NOTIFY_KEEP;
int ret = NVIF_EVENT_KEEP;
spin_lock_irqsave(&fctx->lock, flags);
if (!list_empty(&fctx->pending)) {
@ -165,7 +159,7 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
fence = list_entry(fctx->pending.next, typeof(*fence), head);
chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
if (nouveau_fence_update(chan, fctx))
ret = NVIF_NOTIFY_DROP;
ret = NVIF_EVENT_DROP;
}
spin_unlock_irqrestore(&fctx->lock, flags);
@ -177,12 +171,16 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
{
struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
struct nouveau_cli *cli = (void *)chan->user.client;
struct {
struct nvif_event_v0 base;
struct nvif_chan_event_v0 host;
} args;
int ret;
INIT_LIST_HEAD(&fctx->flip);
INIT_LIST_HEAD(&fctx->pending);
spin_lock_init(&fctx->lock);
fctx->context = chan->drm->chan.context_base + chan->chid;
fctx->context = chan->drm->runl[chan->runlist].context_base + chan->chid;
if (chan == chan->drm->cechan)
strcpy(fctx->name, "copy engine channel");
@ -195,13 +193,12 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
if (!priv->uevent)
return;
ret = nvif_notify_ctor(&chan->user, "fenceNonStallIntr",
nouveau_fence_wait_uevent_handler,
false, NV826E_V0_NTFY_NON_STALL_INTERRUPT,
&(struct nvif_notify_uevent_req) { },
sizeof(struct nvif_notify_uevent_req),
sizeof(struct nvif_notify_uevent_rep),
&fctx->notify);
args.host.version = 0;
args.host.type = NVIF_CHAN_EVENT_V0_NON_STALL_INTR;
ret = nvif_event_ctor(&chan->user, "fenceNonStallIntr", (chan->runlist << 16) | chan->chid,
nouveau_fence_wait_uevent_handler, false,
&args.base, sizeof(args), &fctx->event);
WARN_ON(ret);
}
@ -230,7 +227,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
spin_lock_irq(&fctx->lock);
if (nouveau_fence_update(chan, fctx))
nvif_notify_put(&fctx->notify);
nvif_event_block(&fctx->event);
list_add_tail(&fence->head, &fctx->pending);
spin_unlock_irq(&fctx->lock);
@ -254,7 +251,7 @@ nouveau_fence_done(struct nouveau_fence *fence)
spin_lock_irqsave(&fctx->lock, flags);
chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
if (chan && nouveau_fence_update(chan, fctx))
nvif_notify_put(&fctx->notify);
nvif_event_block(&fctx->event);
spin_unlock_irqrestore(&fctx->lock, flags);
}
return dma_fence_is_signaled(&fence->base);
@ -505,13 +502,13 @@ static bool nouveau_fence_enable_signaling(struct dma_fence *f)
bool ret;
if (!fctx->notify_ref++)
nvif_notify_get(&fctx->notify);
nvif_event_allow(&fctx->event);
ret = nouveau_fence_no_signaling(f);
if (ret)
set_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags);
else if (!--fctx->notify_ref)
nvif_notify_put(&fctx->notify);
nvif_event_block(&fctx->event);
return ret;
}

View file

@ -3,7 +3,7 @@
#define __NOUVEAU_FENCE_H__
#include <linux/dma-fence.h>
#include <nvif/notify.h>
#include <nvif/event.h>
struct nouveau_drm;
struct nouveau_bo;
@ -44,7 +44,7 @@ struct nouveau_fence_chan {
u32 context;
char name[32];
struct nvif_notify notify;
struct nvif_event event;
int notify_ref, dead;
};

View file

@ -27,12 +27,10 @@
******************************************************************************/
#include <core/client.h>
#include <core/notify.h>
#include <core/ioctl.h>
#include <nvif/client.h>
#include <nvif/driver.h>
#include <nvif/notify.h>
#include <nvif/event.h>
#include <nvif/ioctl.h>
@ -71,11 +69,24 @@ nvkm_client_suspend(void *priv)
return nvkm_object_fini(&client->object, true);
}
static int
nvkm_client_event(u64 token, void *repv, u32 repc)
{
struct nvif_object *object = (void *)(unsigned long)token;
struct nvif_event *event = container_of(object, typeof(*event), object);
if (event->func(event, repv, repc) == NVIF_EVENT_KEEP)
return NVKM_EVENT_KEEP;
return NVKM_EVENT_DROP;
}
static int
nvkm_client_driver_init(const char *name, u64 device, const char *cfg,
const char *dbg, void **ppriv)
{
return nvkm_client_new(name, device, cfg, dbg, nvif_notify, (struct nvkm_client **)ppriv);
return nvkm_client_new(name, device, cfg, dbg, nvkm_client_event,
(struct nvkm_client **)ppriv);
}
const struct nvif_driver

View file

@ -24,7 +24,7 @@
#include "nouveau_chan.h"
#include "nouveau_dmem.h"
#include <nvif/notify.h>
#include <nvif/event.h>
#include <nvif/object.h>
#include <nvif/vmm.h>
@ -51,7 +51,8 @@ struct nouveau_svm {
u32 putaddr;
u32 get;
u32 put;
struct nvif_notify notify;
struct nvif_event notify;
struct work_struct work;
struct nouveau_svm_fault {
u64 inst;
@ -711,13 +712,11 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
return ret;
}
static int
nouveau_svm_fault(struct nvif_notify *notify)
static void
nouveau_svm_fault(struct work_struct *work)
{
struct nouveau_svm_fault_buffer *buffer =
container_of(notify, typeof(*buffer), notify);
struct nouveau_svm *svm =
container_of(buffer, typeof(*svm), buffer[buffer->id]);
struct nouveau_svm_fault_buffer *buffer = container_of(work, typeof(*buffer), work);
struct nouveau_svm *svm = container_of(buffer, typeof(*svm), buffer[buffer->id]);
struct nvif_object *device = &svm->drm->client.device.object;
struct nouveau_svmm *svmm;
struct {
@ -737,7 +736,7 @@ nouveau_svm_fault(struct nvif_notify *notify)
buffer->put = nvif_rd32(device, buffer->putaddr);
buffer->get = nvif_rd32(device, buffer->getaddr);
if (buffer->get == buffer->put)
return NVIF_NOTIFY_KEEP;
return;
}
buffer->fault_nr = 0;
@ -881,7 +880,15 @@ nouveau_svm_fault(struct nvif_notify *notify)
/* Issue fault replay to the GPU. */
if (replay)
nouveau_svm_fault_replay(svm);
return NVIF_NOTIFY_KEEP;
}
static int
nouveau_svm_event(struct nvif_event *event, void *argv, u32 argc)
{
struct nouveau_svm_fault_buffer *buffer = container_of(event, typeof(*buffer), notify);
schedule_work(&buffer->work);
return NVIF_EVENT_KEEP;
}
static struct nouveau_pfnmap_args *
@ -936,7 +943,9 @@ static void
nouveau_svm_fault_buffer_fini(struct nouveau_svm *svm, int id)
{
struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
nvif_notify_put(&buffer->notify);
nvif_event_block(&buffer->notify);
flush_work(&buffer->work);
}
static int
@ -944,10 +953,12 @@ nouveau_svm_fault_buffer_init(struct nouveau_svm *svm, int id)
{
struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
struct nvif_object *device = &svm->drm->client.device.object;
buffer->get = nvif_rd32(device, buffer->getaddr);
buffer->put = nvif_rd32(device, buffer->putaddr);
SVM_DBG(svm, "get %08x put %08x (init)", buffer->get, buffer->put);
return nvif_notify_get(&buffer->notify);
return nvif_event_allow(&buffer->notify);
}
static void
@ -956,15 +967,18 @@ nouveau_svm_fault_buffer_dtor(struct nouveau_svm *svm, int id)
struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
int i;
if (!nvif_object_constructed(&buffer->object))
return;
nouveau_svm_fault_buffer_fini(svm, id);
if (buffer->fault) {
for (i = 0; buffer->fault[i] && i < buffer->entries; i++)
kfree(buffer->fault[i]);
kvfree(buffer->fault);
}
nouveau_svm_fault_buffer_fini(svm, id);
nvif_notify_dtor(&buffer->notify);
nvif_event_dtor(&buffer->notify);
nvif_object_dtor(&buffer->object);
}
@ -990,10 +1004,10 @@ nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id)
buffer->entries = args.entries;
buffer->getaddr = args.get;
buffer->putaddr = args.put;
INIT_WORK(&buffer->work, nouveau_svm_fault);
ret = nvif_notify_ctor(&buffer->object, "svmFault", nouveau_svm_fault,
true, NVB069_V0_NTFY_FAULT, NULL, 0, 0,
&buffer->notify);
ret = nvif_event_ctor(&buffer->object, "svmFault", id, nouveau_svm_event, true, NULL, 0,
&buffer->notify);
if (ret)
return ret;

View file

@ -151,12 +151,6 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
case NVIF_IOCTL_V0_NEW:
ret = usif_object_new(filp, data, size, argv, argc, abi16);
break;
case NVIF_IOCTL_V0_NTFY_NEW:
case NVIF_IOCTL_V0_NTFY_DEL:
case NVIF_IOCTL_V0_NTFY_GET:
case NVIF_IOCTL_V0_NTFY_PUT:
ret = -ENOSYS;
break;
default:
ret = nvif_client_ioctl(client, argv, argc);
break;

View file

@ -7,7 +7,6 @@
#include "nouveau_drv.h"
#include "nouveau_acpi.h"
#include "nouveau_fbcon.h"
#include "nouveau_vga.h"
static unsigned int

View file

@ -1,259 +0,0 @@
/*
* Copyright 2009 Ben Skeggs
* Copyright 2008 Stuart Bennett
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#define NVIF_DEBUG_PRINT_DISABLE
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
#include <nvif/push006c.h>
int
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret;
ret = PUSH_WAIT(push, 4);
if (ret)
return ret;
PUSH_NVSQ(push, NV05F, 0x0300, (region->sy << 16) | region->sx,
0x0304, (region->dy << 16) | region->dx,
0x0308, (region->height << 16) | region->width);
PUSH_KICK(push);
return 0;
}
int
nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret;
ret = PUSH_WAIT(push, 7);
if (ret)
return ret;
PUSH_NVSQ(push, NV04A, 0x02fc, (rect->rop != ROP_COPY) ? 1 : 3);
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
PUSH_NVSQ(push, NV04A, 0x03fc, ((uint32_t *)info->pseudo_palette)[rect->color]);
else
PUSH_NVSQ(push, NV04A, 0x03fc, rect->color);
PUSH_NVSQ(push, NV04A, 0x0400, (rect->dx << 16) | rect->dy,
0x0404, (rect->width << 16) | rect->height);
PUSH_KICK(push);
return 0;
}
int
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
uint32_t fg;
uint32_t bg;
uint32_t dsize;
uint32_t *data = (uint32_t *)image->data;
int ret;
if (image->depth != 1)
return -ENODEV;
ret = PUSH_WAIT(push, 8);
if (ret)
return ret;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
} else {
fg = image->fg_color;
bg = image->bg_color;
}
PUSH_NVSQ(push, NV04A, 0x0be4, (image->dy << 16) | (image->dx & 0xffff),
0x0be8, ((image->dy + image->height) << 16) |
((image->dx + image->width) & 0xffff),
0x0bec, bg,
0x0bf0, fg,
0x0bf4, (image->height << 16) | ALIGN(image->width, 8),
0x0bf8, (image->height << 16) | image->width,
0x0bfc, (image->dy << 16) | (image->dx & 0xffff));
dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
while (dsize) {
int iter_len = dsize > 128 ? 128 : dsize;
ret = PUSH_WAIT(push, iter_len + 1);
if (ret)
return ret;
PUSH_NVSQ(push, NV04A, 0x0c00, data, iter_len);
data += iter_len;
dsize -= iter_len;
}
PUSH_KICK(push);
return 0;
}
int
nv04_fbcon_accel_init(struct fb_info *info)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->helper.dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_device *device = &drm->client.device;
struct nvif_push *push = chan->chan.push;
struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device);
resource_size_t fb_base = nvkm_device->func->resource_addr(nvkm_device, 1);
int surface_fmt, pattern_fmt, rect_fmt;
int ret;
switch (info->var.bits_per_pixel) {
case 8:
surface_fmt = 1;
pattern_fmt = 3;
rect_fmt = 3;
break;
case 16:
surface_fmt = 4;
pattern_fmt = 1;
rect_fmt = 1;
break;
case 32:
switch (info->var.transp.length) {
case 0: /* depth 24 */
case 8: /* depth 32 */
break;
default:
return -EINVAL;
}
surface_fmt = 6;
pattern_fmt = 3;
rect_fmt = 3;
break;
default:
return -EINVAL;
}
ret = nvif_object_ctor(&chan->user, "fbconCtxSurf2d", 0x0062,
device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ?
0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconCtxClip", 0x0019, 0x0019,
NULL, 0, &nfbdev->clip);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconCtxRop", 0x0043, 0x0043,
NULL, 0, &nfbdev->rop);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconCtxPatt", 0x0044, 0x0044,
NULL, 0, &nfbdev->patt);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconGdiRectText", 0x004a, 0x004a,
NULL, 0, &nfbdev->gdi);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconImageBlit", 0x005f,
device->info.chipset >= 0x11 ? 0x009f : 0x005f,
NULL, 0, &nfbdev->blit);
if (ret)
return ret;
if (PUSH_WAIT(push, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
nouveau_fbcon_gpu_lockup(info);
return 0;
}
PUSH_NVSQ(push, NV042, 0x0000, nfbdev->surf2d.handle);
PUSH_NVSQ(push, NV042, 0x0184, chan->vram.handle,
0x0188, chan->vram.handle);
PUSH_NVSQ(push, NV042, 0x0300, surface_fmt,
0x0304, info->fix.line_length | (info->fix.line_length << 16),
0x0308, info->fix.smem_start - fb_base,
0x030c, info->fix.smem_start - fb_base);
PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle);
PUSH_NVSQ(push, NV043, 0x0300, 0x55);
PUSH_NVSQ(push, NV044, 0x0000, nfbdev->patt.handle);
PUSH_NVSQ(push, NV044, 0x0300, pattern_fmt,
#ifdef __BIG_ENDIAN
0x0304, 2,
#else
0x0304, 1,
#endif
0x0308, 0,
0x030c, 1,
0x0310, ~0,
0x0314, ~0,
0x0318, ~0,
0x031c, ~0);
PUSH_NVSQ(push, NV019, 0x0000, nfbdev->clip.handle);
PUSH_NVSQ(push, NV019, 0x0300, 0,
0x0304, (info->var.yres_virtual << 16) | info->var.xres_virtual);
PUSH_NVSQ(push, NV05F, 0x0000, nfbdev->blit.handle);
PUSH_NVSQ(push, NV05F, 0x019c, nfbdev->surf2d.handle);
PUSH_NVSQ(push, NV05F, 0x02fc, 3);
if (nfbdev->blit.oclass == 0x009f) {
PUSH_NVSQ(push, NV09F, 0x0120, 0,
0x0124, 1,
0x0128, 2);
}
PUSH_NVSQ(push, NV04A, 0x0000, nfbdev->gdi.handle);
PUSH_NVSQ(push, NV04A, 0x0198, nfbdev->surf2d.handle);
PUSH_NVSQ(push, NV04A, 0x0188, nfbdev->patt.handle,
0x018c, nfbdev->rop.handle);
PUSH_NVSQ(push, NV04A, 0x0304, 1);
PUSH_NVSQ(push, NV04A, 0x0300, rect_fmt);
PUSH_NVSQ(push, NV04A, 0x02fc, 3);
PUSH_KICK(push);
return 0;
}

View file

@ -1,299 +0,0 @@
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#define NVIF_DEBUG_PRINT_DISABLE
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
#include "nouveau_vmm.h"
#include <nvif/push206e.h>
#include <nvhw/class/cl502d.h>
int
nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
u32 colour;
int ret;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
colour = ((uint32_t *)info->pseudo_palette)[rect->color];
else
colour = rect->color;
ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 11);
if (ret)
return ret;
if (rect->rop != ROP_COPY) {
PUSH_MTHD(push, NV502D, SET_OPERATION,
NVDEF(NV502D, SET_OPERATION, V, ROP_AND));
}
PUSH_MTHD(push, NV502D, SET_RENDER_SOLID_PRIM_COLOR, colour);
PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx,
RENDER_SOLID_PRIM_POINT_Y(0), rect->dy,
RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width,
RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height);
if (rect->rop != ROP_COPY) {
PUSH_MTHD(push, NV502D, SET_OPERATION,
NVDEF(NV502D, SET_OPERATION, V, SRCCOPY));
}
PUSH_KICK(push);
return 0;
}
int
nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret;
ret = PUSH_WAIT(push, 12);
if (ret)
return ret;
PUSH_MTHD(push, NV502D, WAIT_FOR_IDLE, 0);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx,
SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy,
SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width,
SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0,
SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx,
SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0,
PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy);
PUSH_KICK(push);
return 0;
}
int
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
uint32_t dwords, *data = (uint32_t *)image->data;
uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
uint32_t *palette = info->pseudo_palette, bg, fg;
int ret;
if (image->depth != 1)
return -ENODEV;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
bg = palette[image->bg_color] | mask;
fg = palette[image->fg_color] | mask;
} else {
bg = image->bg_color;
fg = image->fg_color;
}
ret = PUSH_WAIT(push, 11);
if (ret)
return ret;
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_COLOR0, bg,
SET_PIXELS_FROM_CPU_COLOR1, fg);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width,
SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0,
SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx,
SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0,
SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy);
dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
while (dwords) {
int count = dwords > 2047 ? 2047 : dwords;
ret = PUSH_WAIT(push, count + 1);
if (ret)
return ret;
dwords -= count;
PUSH_NINC(push, NV502D, PIXELS_FROM_CPU_DATA, data, count);
data += count;
}
PUSH_KICK(push);
return 0;
}
int
nv50_fbcon_accel_init(struct fb_info *info)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->helper.dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret, format;
switch (info->var.bits_per_pixel) {
case 8:
format = NV502D_SET_DST_FORMAT_V_Y8;
break;
case 15:
format = NV502D_SET_DST_FORMAT_V_X1R5G5B5;
break;
case 16:
format = NV502D_SET_DST_FORMAT_V_R5G6B5;
break;
case 32:
switch (info->var.transp.length) {
case 0: /* depth 24 */
case 8: /* depth 32, just use 24.. */
format = NV502D_SET_DST_FORMAT_V_X8R8G8B8;
break;
case 2: /* depth 30 */
format = NV502D_SET_DST_FORMAT_V_A2B10G10R10;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x502d, 0x502d,
NULL, 0, &nfbdev->twod);
if (ret)
return ret;
ret = PUSH_WAIT(push, 56);
if (ret) {
nouveau_fbcon_gpu_lockup(info);
return ret;
}
PUSH_MTHD(push, NV502D, SET_OBJECT, nfbdev->twod.handle);
PUSH_MTHD(push, NV502D, SET_DST_CONTEXT_DMA, chan->vram.handle,
SET_SRC_CONTEXT_DMA, chan->vram.handle,
SET_SEMAPHORE_CONTEXT_DMA, chan->vram.handle);
PUSH_MTHD(push, NV502D, SET_DST_FORMAT,
NVVAL(NV502D, SET_DST_FORMAT, V, format),
SET_DST_MEMORY_LAYOUT,
NVDEF(NV502D, SET_DST_MEMORY_LAYOUT, V, PITCH));
PUSH_MTHD(push, NV502D, SET_DST_PITCH, info->fix.line_length,
SET_DST_WIDTH, info->var.xres_virtual,
SET_DST_HEIGHT, info->var.yres_virtual,
SET_DST_OFFSET_UPPER,
NVVAL(NV502D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
SET_DST_OFFSET_LOWER,
NVVAL(NV502D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
PUSH_MTHD(push, NV502D, SET_SRC_FORMAT,
NVVAL(NV502D, SET_SRC_FORMAT, V, format),
SET_SRC_MEMORY_LAYOUT,
NVDEF(NV502D, SET_SRC_MEMORY_LAYOUT, V, PITCH));
PUSH_MTHD(push, NV502D, SET_SRC_PITCH, info->fix.line_length,
SET_SRC_WIDTH, info->var.xres_virtual,
SET_SRC_HEIGHT, info->var.yres_virtual,
SET_SRC_OFFSET_UPPER,
NVVAL(NV502D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
SET_SRC_OFFSET_LOWER,
NVVAL(NV502D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
PUSH_MTHD(push, NV502D, SET_CLIP_ENABLE,
NVDEF(NV502D, SET_CLIP_ENABLE, V, FALSE));
PUSH_MTHD(push, NV502D, SET_ROP,
NVVAL(NV502D, SET_ROP, V, 0x55));
PUSH_MTHD(push, NV502D, SET_OPERATION,
NVDEF(NV502D, SET_OPERATION, V, SRCCOPY));
PUSH_MTHD(push, NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT,
NVDEF(NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8),
SET_MONOCHROME_PATTERN_FORMAT,
NVDEF(NV502D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1));
PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_MODE,
NVDEF(NV502D, RENDER_SOLID_PRIM_MODE, V, RECTS),
SET_RENDER_SOLID_PRIM_COLOR_FORMAT,
NVVAL(NV502D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format));
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX),
SET_PIXELS_FROM_CPU_COLOR_FORMAT,
NVVAL(NV502D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format),
SET_PIXELS_FROM_CPU_INDEX_FORMAT,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1),
SET_PIXELS_FROM_CPU_MONO_FORMAT,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1),
SET_PIXELS_FROM_CPU_WRAP,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE));
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE));
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0,
SET_PIXELS_FROM_CPU_DX_DU_INT, 1,
SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0,
SET_PIXELS_FROM_CPU_DY_DV_INT, 1);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP,
NVDEF(NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE));
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0,
SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1,
SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0,
SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1);
PUSH_KICK(push);
return 0;
}

View file

@ -76,12 +76,18 @@ nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
return ret;
}
static inline u32
nv84_fence_chid(struct nouveau_channel *chan)
{
return chan->drm->runl[chan->runlist].chan_id_base + chan->chid;
}
static int
nv84_fence_emit(struct nouveau_fence *fence)
{
struct nouveau_channel *chan = fence->channel;
struct nv84_fence_chan *fctx = chan->fence;
u64 addr = fctx->vma->addr + chan->chid * 16;
u64 addr = fctx->vma->addr + nv84_fence_chid(chan) * 16;
return fctx->base.emit32(chan, addr, fence->base.seqno);
}
@ -91,7 +97,7 @@ nv84_fence_sync(struct nouveau_fence *fence,
struct nouveau_channel *prev, struct nouveau_channel *chan)
{
struct nv84_fence_chan *fctx = chan->fence;
u64 addr = fctx->vma->addr + prev->chid * 16;
u64 addr = fctx->vma->addr + nv84_fence_chid(prev) * 16;
return fctx->base.sync32(chan, addr, fence->base.seqno);
}
@ -100,7 +106,7 @@ static u32
nv84_fence_read(struct nouveau_channel *chan)
{
struct nv84_fence_priv *priv = chan->drm->fence;
return nouveau_bo_rd32(priv->bo, chan->chid * 16/4);
return nouveau_bo_rd32(priv->bo, nv84_fence_chid(chan) * 16/4);
}
static void
@ -109,7 +115,7 @@ nv84_fence_context_del(struct nouveau_channel *chan)
struct nv84_fence_priv *priv = chan->drm->fence;
struct nv84_fence_chan *fctx = chan->fence;
nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence);
nouveau_bo_wr32(priv->bo, nv84_fence_chid(chan) * 16 / 4, fctx->base.sequence);
mutex_lock(&priv->mutex);
nouveau_vma_del(&fctx->vma);
mutex_unlock(&priv->mutex);
@ -152,9 +158,9 @@ nv84_fence_suspend(struct nouveau_drm *drm)
struct nv84_fence_priv *priv = drm->fence;
int i;
priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan.nr));
priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan_total));
if (priv->suspend) {
for (i = 0; i < drm->chan.nr; i++)
for (i = 0; i < drm->chan_total; i++)
priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4);
}
@ -168,7 +174,7 @@ nv84_fence_resume(struct nouveau_drm *drm)
int i;
if (priv->suspend) {
for (i = 0; i < drm->chan.nr; i++)
for (i = 0; i < drm->chan_total; i++)
nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]);
vfree(priv->suspend);
priv->suspend = NULL;
@ -204,7 +210,7 @@ nv84_fence_create(struct nouveau_drm *drm)
priv->base.context_new = nv84_fence_context_new;
priv->base.context_del = nv84_fence_context_del;
priv->base.uevent = drm->client.device.info.family < NV_DEVICE_INFO_V0_AMPERE;
priv->base.uevent = true;
mutex_init(&priv->mutex);
@ -216,7 +222,7 @@ nv84_fence_create(struct nouveau_drm *drm)
* will lose CPU/GPU coherency!
*/
NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT;
ret = nouveau_bo_new(&drm->client, 16 * drm->chan.nr, 0,
ret = nouveau_bo_new(&drm->client, 16 * drm->chan_total, 0,
domain, 0, 0, NULL, NULL, &priv->bo);
if (ret == 0) {
ret = nouveau_bo_pin(priv->bo, domain, false);

View file

@ -1,297 +0,0 @@
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#define NVIF_DEBUG_PRINT_DISABLE
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
#include "nouveau_vmm.h"
#include <nvif/push906f.h>
#include <nvhw/class/cl902d.h>
int
nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
u32 colour;
int ret;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
colour = ((uint32_t *)info->pseudo_palette)[rect->color];
else
colour = rect->color;
ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 9);
if (ret)
return ret;
if (rect->rop != ROP_COPY) {
PUSH_IMMD(push, NV902D, SET_OPERATION,
NVDEF(NV902D, SET_OPERATION, V, ROP_AND));
}
PUSH_MTHD(push, NV902D, SET_RENDER_SOLID_PRIM_COLOR, colour);
PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx,
RENDER_SOLID_PRIM_POINT_Y(0), rect->dy,
RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width,
RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height);
if (rect->rop != ROP_COPY) {
PUSH_IMMD(push, NV902D, SET_OPERATION,
NVDEF(NV902D, SET_OPERATION, V, SRCCOPY));
}
PUSH_KICK(push);
return 0;
}
int
nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret;
ret = PUSH_WAIT(push, 11);
if (ret)
return ret;
PUSH_IMMD(push, NV902D, WAIT_FOR_IDLE, 0);
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx,
SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy,
SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width,
SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height);
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0,
SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx,
SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0,
PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy);
PUSH_KICK(push);
return 0;
}
int
nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
uint32_t dwords, *data = (uint32_t *)image->data;
uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
uint32_t *palette = info->pseudo_palette, bg, fg;
int ret;
if (image->depth != 1)
return -ENODEV;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
bg = palette[image->bg_color] | mask;
fg = palette[image->fg_color] | mask;
} else {
bg = image->bg_color;
fg = image->fg_color;
}
ret = PUSH_WAIT(push, 11);
if (ret)
return ret;
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_COLOR0, bg,
SET_PIXELS_FROM_CPU_COLOR1, fg);
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width,
SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height);
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0,
SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx,
SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0,
SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy);
dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
while (dwords) {
int count = dwords > 2047 ? 2047 : dwords;
ret = PUSH_WAIT(push, count + 1);
if (ret)
return ret;
dwords -= count;
PUSH_NINC(push, NV902D, PIXELS_FROM_CPU_DATA, data, count);
data += count;
}
PUSH_KICK(push);
return 0;
}
int
nvc0_fbcon_accel_init(struct fb_info *info)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->helper.dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret, format;
ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x902d, 0x902d,
NULL, 0, &nfbdev->twod);
if (ret)
return ret;
switch (info->var.bits_per_pixel) {
case 8:
format = NV902D_SET_DST_FORMAT_V_Y8;
break;
case 15:
format = NV902D_SET_DST_FORMAT_V_X1R5G5B5;
break;
case 16:
format = NV902D_SET_DST_FORMAT_V_R5G6B5;
break;
case 32:
switch (info->var.transp.length) {
case 0: /* depth 24 */
case 8: /* depth 32, just use 24.. */
format = NV902D_SET_DST_FORMAT_V_X8R8G8B8;
break;
case 2: /* depth 30 */
format = NV902D_SET_DST_FORMAT_V_A2B10G10R10;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
ret = PUSH_WAIT(push, 52);
if (ret) {
WARN_ON(1);
nouveau_fbcon_gpu_lockup(info);
return ret;
}
PUSH_MTHD(push, NV902D, SET_OBJECT, nfbdev->twod.handle);
PUSH_MTHD(push, NV902D, SET_DST_FORMAT,
NVVAL(NV902D, SET_DST_FORMAT, V, format),
SET_DST_MEMORY_LAYOUT,
NVDEF(NV902D, SET_DST_MEMORY_LAYOUT, V, PITCH));
PUSH_MTHD(push, NV902D, SET_DST_PITCH, info->fix.line_length,
SET_DST_WIDTH, info->var.xres_virtual,
SET_DST_HEIGHT, info->var.yres_virtual,
SET_DST_OFFSET_UPPER,
NVVAL(NV902D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
SET_DST_OFFSET_LOWER,
NVVAL(NV902D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
PUSH_MTHD(push, NV902D, SET_SRC_FORMAT,
NVVAL(NV902D, SET_SRC_FORMAT, V, format),
SET_SRC_MEMORY_LAYOUT,
NVDEF(NV902D, SET_SRC_MEMORY_LAYOUT, V, PITCH));
PUSH_MTHD(push, NV902D, SET_SRC_PITCH, info->fix.line_length,
SET_SRC_WIDTH, info->var.xres_virtual,
SET_SRC_HEIGHT, info->var.yres_virtual,
SET_SRC_OFFSET_UPPER,
NVVAL(NV902D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
SET_SRC_OFFSET_LOWER,
NVVAL(NV902D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
PUSH_IMMD(push, NV902D, SET_CLIP_ENABLE,
NVDEF(NV902D, SET_CLIP_ENABLE, V, FALSE));
PUSH_IMMD(push, NV902D, SET_ROP,
NVVAL(NV902D, SET_ROP, V, 0x55));
PUSH_IMMD(push, NV902D, SET_OPERATION,
NVDEF(NV902D, SET_OPERATION, V, SRCCOPY));
PUSH_MTHD(push, NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT,
NVDEF(NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8),
SET_MONOCHROME_PATTERN_FORMAT,
NVDEF(NV902D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1));
PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_MODE,
NVDEF(NV902D, RENDER_SOLID_PRIM_MODE, V, RECTS),
SET_RENDER_SOLID_PRIM_COLOR_FORMAT,
NVVAL(NV902D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format));
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX),
SET_PIXELS_FROM_CPU_COLOR_FORMAT,
NVVAL(NV902D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format),
SET_PIXELS_FROM_CPU_INDEX_FORMAT,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1),
SET_PIXELS_FROM_CPU_MONO_FORMAT,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1),
SET_PIXELS_FROM_CPU_WRAP,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE));
PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE));
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0,
SET_PIXELS_FROM_CPU_DX_DU_INT, 1,
SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0,
SET_PIXELS_FROM_CPU_DY_DV_INT, 1);
PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP,
NVDEF(NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE));
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0,
SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1,
SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0,
SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1);
PUSH_KICK(push);
return 0;
}

View file

@ -5,10 +5,11 @@ nvif-y += nvif/conn.o
nvif-y += nvif/device.o
nvif-y += nvif/disp.o
nvif-y += nvif/driver.o
nvif-y += nvif/event.o
nvif-y += nvif/fifo.o
nvif-y += nvif/head.o
nvif-y += nvif/mem.o
nvif-y += nvif/mmu.o
nvif-y += nvif/notify.o
nvif-y += nvif/outp.o
nvif-y += nvif/timer.o
nvif-y += nvif/vmm.o

View file

@ -26,6 +26,25 @@
#include <nvif/class.h>
#include <nvif/if0011.h>
int
nvif_conn_event_ctor(struct nvif_conn *conn, const char *name, nvif_event_func func, u8 types,
struct nvif_event *event)
{
struct {
struct nvif_event_v0 base;
struct nvif_conn_event_v0 conn;
} args;
int ret;
args.conn.version = 0;
args.conn.types = types;
ret = nvif_event_ctor_(&conn->object, name ?: "nvifConnHpd", nvif_conn_id(conn),
func, true, &args.base, sizeof(args), false, event);
NVIF_DEBUG(&conn->object, "[NEW EVENT:HPD types:%02x]", types);
return ret;
}
int
nvif_conn_hpd_status(struct nvif_conn *conn)
{

View file

@ -72,9 +72,10 @@ nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct
if (ret)
return ret;
NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x",
args.conn_mask, args.outp_mask);
NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x head_mask:%08x",
args.conn_mask, args.outp_mask, args.head_mask);
disp->conn_mask = args.conn_mask;
disp->outp_mask = args.outp_mask;
disp->head_mask = args.head_mask;
return 0;
}

Some files were not shown because too many files have changed in this diff Show more