Commit 49ff3e79 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-fixes-2024-10-17' of...

Merge tag 'drm-misc-fixes-2024-10-17' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes

Short summary of fixes pull:

ast:
- Clear EDID on unplugged connectors

host1x:
- Fix boot on Tegra186
- Set DMA parameters

mgag200:
- Revert VBLANK support

panel:
- himax-hx83192: Adjust power and gamma

qaic:
- Sgtable loop fixes

vmwgfx:
- Limit display layout allocatino size
- Handle allocation errors in connector checks
- Clean up KMS code for 2d-only setup
- Report surface-check errors correctly
- Remove NULL test around kvfree()
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20241017115516.GA196624@linux.fritz.box
parents 7626b4e9 c09c4f2a
...@@ -496,7 +496,7 @@ static int encode_addr_size_pairs(struct dma_xfer *xfer, struct wrapper_list *wr ...@@ -496,7 +496,7 @@ static int encode_addr_size_pairs(struct dma_xfer *xfer, struct wrapper_list *wr
nents = sgt->nents; nents = sgt->nents;
nents_dma = nents; nents_dma = nents;
*size = QAIC_MANAGE_EXT_MSG_LENGTH - msg_hdr_len - sizeof(**out_trans); *size = QAIC_MANAGE_EXT_MSG_LENGTH - msg_hdr_len - sizeof(**out_trans);
for_each_sgtable_sg(sgt, sg, i) { for_each_sgtable_dma_sg(sgt, sg, i) {
*size -= sizeof(*asp); *size -= sizeof(*asp);
/* Save 1K for possible follow-up transactions. */ /* Save 1K for possible follow-up transactions. */
if (*size < SZ_1K) { if (*size < SZ_1K) {
......
...@@ -184,7 +184,7 @@ static int clone_range_of_sgt_for_slice(struct qaic_device *qdev, struct sg_tabl ...@@ -184,7 +184,7 @@ static int clone_range_of_sgt_for_slice(struct qaic_device *qdev, struct sg_tabl
nents = 0; nents = 0;
size = size ? size : PAGE_SIZE; size = size ? size : PAGE_SIZE;
for (sg = sgt_in->sgl; sg; sg = sg_next(sg)) { for_each_sgtable_dma_sg(sgt_in, sg, j) {
len = sg_dma_len(sg); len = sg_dma_len(sg);
if (!len) if (!len)
...@@ -221,7 +221,7 @@ static int clone_range_of_sgt_for_slice(struct qaic_device *qdev, struct sg_tabl ...@@ -221,7 +221,7 @@ static int clone_range_of_sgt_for_slice(struct qaic_device *qdev, struct sg_tabl
/* copy relevant sg node and fix page and length */ /* copy relevant sg node and fix page and length */
sgn = sgf; sgn = sgf;
for_each_sgtable_sg(sgt, sg, j) { for_each_sgtable_dma_sg(sgt, sg, j) {
memcpy(sg, sgn, sizeof(*sg)); memcpy(sg, sgn, sizeof(*sg));
if (sgn == sgf) { if (sgn == sgf) {
sg_dma_address(sg) += offf; sg_dma_address(sg) += offf;
...@@ -301,7 +301,7 @@ static int encode_reqs(struct qaic_device *qdev, struct bo_slice *slice, ...@@ -301,7 +301,7 @@ static int encode_reqs(struct qaic_device *qdev, struct bo_slice *slice,
* fence. * fence.
*/ */
dev_addr = req->dev_addr; dev_addr = req->dev_addr;
for_each_sgtable_sg(slice->sgt, sg, i) { for_each_sgtable_dma_sg(slice->sgt, sg, i) {
slice->reqs[i].cmd = cmd; slice->reqs[i].cmd = cmd;
slice->reqs[i].src_addr = cpu_to_le64(slice->dir == DMA_TO_DEVICE ? slice->reqs[i].src_addr = cpu_to_le64(slice->dir == DMA_TO_DEVICE ?
sg_dma_address(sg) : dev_addr); sg_dma_address(sg) : dev_addr);
......
...@@ -29,6 +29,8 @@ static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector ...@@ -29,6 +29,8 @@ static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector
if (ast_connector->physical_status == connector_status_connected) { if (ast_connector->physical_status == connector_status_connected) {
count = drm_connector_helper_get_modes(connector); count = drm_connector_helper_get_modes(connector);
} else { } else {
drm_edid_connector_update(connector, NULL);
/* /*
* There's no EDID data without a connected monitor. Set BMC- * There's no EDID data without a connected monitor. Set BMC-
* compatible modes in this case. The XGA default resolution * compatible modes in this case. The XGA default resolution
......
...@@ -29,6 +29,8 @@ static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) ...@@ -29,6 +29,8 @@ static int ast_vga_connector_helper_get_modes(struct drm_connector *connector)
if (ast_connector->physical_status == connector_status_connected) { if (ast_connector->physical_status == connector_status_connected) {
count = drm_connector_helper_get_modes(connector); count = drm_connector_helper_get_modes(connector);
} else { } else {
drm_edid_connector_update(connector, NULL);
/* /*
* There's no EDID data without a connected monitor. Set BMC- * There's no EDID data without a connected monitor. Set BMC-
* compatible modes in this case. The XGA default resolution * compatible modes in this case. The XGA default resolution
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <drm/drm_managed.h> #include <drm/drm_managed.h>
#include <drm/drm_module.h> #include <drm/drm_module.h>
#include <drm/drm_pciids.h> #include <drm/drm_pciids.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -85,34 +84,6 @@ resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size) ...@@ -85,34 +84,6 @@ resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size)
return offset - 65536; return offset - 65536;
} }
static irqreturn_t mgag200_irq_handler(int irq, void *arg)
{
struct drm_device *dev = arg;
struct mga_device *mdev = to_mga_device(dev);
struct drm_crtc *crtc;
u32 status, ien;
status = RREG32(MGAREG_STATUS);
if (status & MGAREG_STATUS_VLINEPEN) {
ien = RREG32(MGAREG_IEN);
if (!(ien & MGAREG_IEN_VLINEIEN))
goto out;
crtc = drm_crtc_from_index(dev, 0);
if (WARN_ON_ONCE(!crtc))
goto out;
drm_crtc_handle_vblank(crtc);
WREG32(MGAREG_ICLEAR, MGAREG_ICLEAR_VLINEICLR);
return IRQ_HANDLED;
}
out:
return IRQ_NONE;
}
/* /*
* DRM driver * DRM driver
*/ */
...@@ -196,7 +167,6 @@ int mgag200_device_init(struct mga_device *mdev, ...@@ -196,7 +167,6 @@ int mgag200_device_init(struct mga_device *mdev,
const struct mgag200_device_funcs *funcs) const struct mgag200_device_funcs *funcs)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct pci_dev *pdev = to_pci_dev(dev->dev);
u8 crtcext3, misc; u8 crtcext3, misc;
int ret; int ret;
...@@ -223,14 +193,6 @@ int mgag200_device_init(struct mga_device *mdev, ...@@ -223,14 +193,6 @@ int mgag200_device_init(struct mga_device *mdev,
mutex_unlock(&mdev->rmmio_lock); mutex_unlock(&mdev->rmmio_lock);
WREG32(MGAREG_IEN, 0); WREG32(MGAREG_IEN, 0);
WREG32(MGAREG_ICLEAR, MGAREG_ICLEAR_VLINEICLR);
ret = devm_request_irq(&pdev->dev, pdev->irq, mgag200_irq_handler, IRQF_SHARED,
dev->driver->name, dev);
if (ret) {
drm_err(dev, "Failed to acquire interrupt, error %d\n", ret);
return ret;
}
return 0; return 0;
} }
......
...@@ -391,24 +391,17 @@ int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_st ...@@ -391,24 +391,17 @@ int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_st
void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state); void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state); void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state); void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
bool mgag200_crtc_helper_get_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq,
int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode);
#define MGAG200_CRTC_HELPER_FUNCS \ #define MGAG200_CRTC_HELPER_FUNCS \
.mode_valid = mgag200_crtc_helper_mode_valid, \ .mode_valid = mgag200_crtc_helper_mode_valid, \
.atomic_check = mgag200_crtc_helper_atomic_check, \ .atomic_check = mgag200_crtc_helper_atomic_check, \
.atomic_flush = mgag200_crtc_helper_atomic_flush, \ .atomic_flush = mgag200_crtc_helper_atomic_flush, \
.atomic_enable = mgag200_crtc_helper_atomic_enable, \ .atomic_enable = mgag200_crtc_helper_atomic_enable, \
.atomic_disable = mgag200_crtc_helper_atomic_disable, \ .atomic_disable = mgag200_crtc_helper_atomic_disable
.get_scanout_position = mgag200_crtc_helper_get_scanout_position
void mgag200_crtc_reset(struct drm_crtc *crtc); void mgag200_crtc_reset(struct drm_crtc *crtc);
struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc); struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc);
void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state); void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state);
int mgag200_crtc_enable_vblank(struct drm_crtc *crtc);
void mgag200_crtc_disable_vblank(struct drm_crtc *crtc);
#define MGAG200_CRTC_FUNCS \ #define MGAG200_CRTC_FUNCS \
.reset = mgag200_crtc_reset, \ .reset = mgag200_crtc_reset, \
...@@ -416,10 +409,7 @@ void mgag200_crtc_disable_vblank(struct drm_crtc *crtc); ...@@ -416,10 +409,7 @@ void mgag200_crtc_disable_vblank(struct drm_crtc *crtc);
.set_config = drm_atomic_helper_set_config, \ .set_config = drm_atomic_helper_set_config, \
.page_flip = drm_atomic_helper_page_flip, \ .page_flip = drm_atomic_helper_page_flip, \
.atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state, \ .atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state, \
.atomic_destroy_state = mgag200_crtc_atomic_destroy_state, \ .atomic_destroy_state = mgag200_crtc_atomic_destroy_state
.enable_vblank = mgag200_crtc_enable_vblank, \
.disable_vblank = mgag200_crtc_disable_vblank, \
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp
void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode, void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode,
bool set_vidrst); bool set_vidrst);
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -404,9 +403,5 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct ...@@ -404,9 +403,5 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
ret = drm_vblank_init(dev, 1);
if (ret)
return ERR_PTR(ret);
return mdev; return mdev;
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -276,9 +275,5 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru ...@@ -276,9 +275,5 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
ret = drm_vblank_init(dev, 1);
if (ret)
return ERR_PTR(ret);
return mdev; return mdev;
} }
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -181,9 +180,5 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, ...@@ -181,9 +180,5 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
ret = drm_vblank_init(dev, 1);
if (ret)
return ERR_PTR(ret);
return mdev; return mdev;
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -206,8 +205,6 @@ static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc, ...@@ -206,8 +205,6 @@ static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc,
mgag200_crtc_set_gamma_linear(mdev, format); mgag200_crtc_set_gamma_linear(mdev, format);
mgag200_enable_display(mdev); mgag200_enable_display(mdev);
drm_crtc_vblank_on(crtc);
} }
static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = {
...@@ -215,8 +212,7 @@ static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = { ...@@ -215,8 +212,7 @@ static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = {
.atomic_check = mgag200_crtc_helper_atomic_check, .atomic_check = mgag200_crtc_helper_atomic_check,
.atomic_flush = mgag200_crtc_helper_atomic_flush, .atomic_flush = mgag200_crtc_helper_atomic_flush,
.atomic_enable = mgag200_g200er_crtc_helper_atomic_enable, .atomic_enable = mgag200_g200er_crtc_helper_atomic_enable,
.atomic_disable = mgag200_crtc_helper_atomic_disable, .atomic_disable = mgag200_crtc_helper_atomic_disable
.get_scanout_position = mgag200_crtc_helper_get_scanout_position,
}; };
static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = { static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = {
...@@ -312,9 +308,5 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru ...@@ -312,9 +308,5 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
ret = drm_vblank_init(dev, 1);
if (ret)
return ERR_PTR(ret);
return mdev; return mdev;
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -207,8 +206,6 @@ static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc, ...@@ -207,8 +206,6 @@ static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc,
mgag200_crtc_set_gamma_linear(mdev, format); mgag200_crtc_set_gamma_linear(mdev, format);
mgag200_enable_display(mdev); mgag200_enable_display(mdev);
drm_crtc_vblank_on(crtc);
} }
static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = {
...@@ -216,8 +213,7 @@ static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = { ...@@ -216,8 +213,7 @@ static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = {
.atomic_check = mgag200_crtc_helper_atomic_check, .atomic_check = mgag200_crtc_helper_atomic_check,
.atomic_flush = mgag200_crtc_helper_atomic_flush, .atomic_flush = mgag200_crtc_helper_atomic_flush,
.atomic_enable = mgag200_g200ev_crtc_helper_atomic_enable, .atomic_enable = mgag200_g200ev_crtc_helper_atomic_enable,
.atomic_disable = mgag200_crtc_helper_atomic_disable, .atomic_disable = mgag200_crtc_helper_atomic_disable
.get_scanout_position = mgag200_crtc_helper_get_scanout_position,
}; };
static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = { static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = {
...@@ -317,9 +313,5 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru ...@@ -317,9 +313,5 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
ret = drm_vblank_init(dev, 1);
if (ret)
return ERR_PTR(ret);
return mdev; return mdev;
} }
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -199,9 +198,5 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, ...@@ -199,9 +198,5 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
ret = drm_vblank_init(dev, 1);
if (ret)
return ERR_PTR(ret);
return mdev; return mdev;
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -338,8 +337,6 @@ static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc, ...@@ -338,8 +337,6 @@ static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc,
mgag200_crtc_set_gamma_linear(mdev, format); mgag200_crtc_set_gamma_linear(mdev, format);
mgag200_enable_display(mdev); mgag200_enable_display(mdev);
drm_crtc_vblank_on(crtc);
} }
static const struct drm_crtc_helper_funcs mgag200_g200se_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs mgag200_g200se_crtc_helper_funcs = {
...@@ -347,8 +344,7 @@ static const struct drm_crtc_helper_funcs mgag200_g200se_crtc_helper_funcs = { ...@@ -347,8 +344,7 @@ static const struct drm_crtc_helper_funcs mgag200_g200se_crtc_helper_funcs = {
.atomic_check = mgag200_crtc_helper_atomic_check, .atomic_check = mgag200_crtc_helper_atomic_check,
.atomic_flush = mgag200_crtc_helper_atomic_flush, .atomic_flush = mgag200_crtc_helper_atomic_flush,
.atomic_enable = mgag200_g200se_crtc_helper_atomic_enable, .atomic_enable = mgag200_g200se_crtc_helper_atomic_enable,
.atomic_disable = mgag200_crtc_helper_atomic_disable, .atomic_disable = mgag200_crtc_helper_atomic_disable
.get_scanout_position = mgag200_crtc_helper_get_scanout_position,
}; };
static const struct drm_crtc_funcs mgag200_g200se_crtc_funcs = { static const struct drm_crtc_funcs mgag200_g200se_crtc_funcs = {
...@@ -517,9 +513,5 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru ...@@ -517,9 +513,5 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
ret = drm_vblank_init(dev, 1);
if (ret)
return ERR_PTR(ret);
return mdev; return mdev;
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -323,9 +322,5 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru ...@@ -323,9 +322,5 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
ret = drm_vblank_init(dev, 1);
if (ret)
return ERR_PTR(ret);
return mdev; return mdev;
} }
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_panic.h> #include <drm/drm_panic.h>
#include <drm/drm_print.h> #include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include "mgag200_ddc.h" #include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
...@@ -227,14 +226,7 @@ void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mod ...@@ -227,14 +226,7 @@ void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mod
vblkstr = mode->crtc_vblank_start; vblkstr = mode->crtc_vblank_start;
vblkend = vtotal + 1; vblkend = vtotal + 1;
/* linecomp = vdispend;
* There's no VBLANK interrupt on Matrox chipsets, so we use
* the VLINE interrupt instead. It triggers when the current
* <linecomp> has been reached. For VBLANK, this is the first
* non-visible line at the bottom of the screen. Therefore,
* keep <linecomp> in sync with <vblkstr>.
*/
linecomp = vblkstr;
misc = RREG8(MGA_MISC_IN); misc = RREG8(MGA_MISC_IN);
...@@ -645,8 +637,6 @@ void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_s ...@@ -645,8 +637,6 @@ void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_s
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev); struct mga_device *mdev = to_mga_device(dev);
struct drm_pending_vblank_event *event;
unsigned long flags;
if (crtc_state->enable && crtc_state->color_mgmt_changed) { if (crtc_state->enable && crtc_state->color_mgmt_changed) {
const struct drm_format_info *format = mgag200_crtc_state->format; const struct drm_format_info *format = mgag200_crtc_state->format;
...@@ -656,18 +646,6 @@ void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_s ...@@ -656,18 +646,6 @@ void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_s
else else
mgag200_crtc_set_gamma_linear(mdev, format); mgag200_crtc_set_gamma_linear(mdev, format);
} }
event = crtc->state->event;
if (event) {
crtc->state->event = NULL;
spin_lock_irqsave(&dev->event_lock, flags);
if (drm_crtc_vblank_get(crtc) != 0)
drm_crtc_send_vblank_event(crtc, event);
else
drm_crtc_arm_vblank_event(crtc, event);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
} }
void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state) void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
...@@ -692,44 +670,15 @@ void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_ ...@@ -692,44 +670,15 @@ void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_
mgag200_crtc_set_gamma_linear(mdev, format); mgag200_crtc_set_gamma_linear(mdev, format);
mgag200_enable_display(mdev); mgag200_enable_display(mdev);
drm_crtc_vblank_on(crtc);
} }
void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state) void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{ {
struct mga_device *mdev = to_mga_device(crtc->dev); struct mga_device *mdev = to_mga_device(crtc->dev);
drm_crtc_vblank_off(crtc);
mgag200_disable_display(mdev); mgag200_disable_display(mdev);
} }
bool mgag200_crtc_helper_get_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq,
int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode)
{
struct mga_device *mdev = to_mga_device(crtc->dev);
u32 vcount;
if (stime)
*stime = ktime_get();
if (vpos) {
vcount = RREG32(MGAREG_VCOUNT);
*vpos = vcount & GENMASK(11, 0);
}
if (hpos)
*hpos = mode->htotal >> 1; // near middle of scanline on average
if (etime)
*etime = ktime_get();
return true;
}
void mgag200_crtc_reset(struct drm_crtc *crtc) void mgag200_crtc_reset(struct drm_crtc *crtc)
{ {
struct mgag200_crtc_state *mgag200_crtc_state; struct mgag200_crtc_state *mgag200_crtc_state;
...@@ -774,30 +723,6 @@ void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_st ...@@ -774,30 +723,6 @@ void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_st
kfree(mgag200_crtc_state); kfree(mgag200_crtc_state);
} }
int mgag200_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct mga_device *mdev = to_mga_device(crtc->dev);
u32 ien;
WREG32(MGAREG_ICLEAR, MGAREG_ICLEAR_VLINEICLR);
ien = RREG32(MGAREG_IEN);
ien |= MGAREG_IEN_VLINEIEN;
WREG32(MGAREG_IEN, ien);
return 0;
}
void mgag200_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct mga_device *mdev = to_mga_device(crtc->dev);
u32 ien;
ien = RREG32(MGAREG_IEN);
ien &= ~(MGAREG_IEN_VLINEIEN);
WREG32(MGAREG_IEN, ien);
}
/* /*
* Mode config * Mode config
*/ */
......
...@@ -298,7 +298,7 @@ static int ivo_t109nw41_init(struct hx83102 *ctx) ...@@ -298,7 +298,7 @@ static int ivo_t109nw41_init(struct hx83102 *ctx)
msleep(60); msleep(60);
hx83102_enable_extended_cmds(&dsi_ctx, true); hx83102_enable_extended_cmds(&dsi_ctx, true);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x2c, 0xed, 0xed, 0x0f, 0xcf, 0x42, mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x2c, 0xed, 0xed, 0x27, 0xe7, 0x52,
0xf5, 0x39, 0x36, 0x36, 0x36, 0x36, 0x32, 0x8b, 0x11, 0x65, 0x00, 0x88, 0xf5, 0x39, 0x36, 0x36, 0x36, 0x36, 0x32, 0x8b, 0x11, 0x65, 0x00, 0x88,
0xfa, 0xff, 0xff, 0x8f, 0xff, 0x08, 0xd6, 0x33); 0xfa, 0xff, 0xff, 0x8f, 0xff, 0x08, 0xd6, 0x33);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x47, 0xb0, 0x80, 0x00, 0x12, mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x47, 0xb0, 0x80, 0x00, 0x12,
...@@ -343,11 +343,11 @@ static int ivo_t109nw41_init(struct hx83102 *ctx) ...@@ -343,11 +343,11 @@ static int ivo_t109nw41_init(struct hx83102 *ctx)
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGMA, 0x04, 0x04, 0x06, 0x0a, 0x0a, 0x05, mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGMA, 0x00, 0x07, 0x10, 0x17, 0x1c, 0x33,
0x12, 0x14, 0x17, 0x13, 0x2c, 0x33, 0x39, 0x4b, 0x4c, 0x56, 0x61, 0x78, 0x48, 0x50, 0x57, 0x50, 0x68, 0x6e, 0x71, 0x7f, 0x81, 0x8a, 0x8e, 0x9b,
0x7a, 0x41, 0x50, 0x68, 0x73, 0x04, 0x04, 0x06, 0x0a, 0x0a, 0x05, 0x12, 0x9c, 0x4d, 0x56, 0x5d, 0x73, 0x00, 0x07, 0x10, 0x17, 0x1c, 0x33, 0x48,
0x14, 0x17, 0x13, 0x2c, 0x33, 0x39, 0x4b, 0x4c, 0x56, 0x61, 0x78, 0x7a, 0x50, 0x57, 0x50, 0x68, 0x6e, 0x71, 0x7f, 0x81, 0x8a, 0x8e, 0x9b, 0x9c,
0x41, 0x50, 0x68, 0x73); 0x4d, 0x56, 0x5d, 0x73);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x07, 0x10, 0x10, 0x1a, 0x26, 0x9e, mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x07, 0x10, 0x10, 0x1a, 0x26, 0x9e,
0x00, 0x4f, 0xa0, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0a, 0x02, 0x00, 0x4f, 0xa0, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0a, 0x02,
0x02, 0x00, 0x33, 0x02, 0x04, 0x18, 0x01); 0x02, 0x00, 0x33, 0x02, 0x04, 0x18, 0x01);
......
...@@ -635,9 +635,7 @@ int vmw_bo_cpu_blit(struct vmw_bo *vmw_dst, ...@@ -635,9 +635,7 @@ int vmw_bo_cpu_blit(struct vmw_bo *vmw_dst,
kunmap_atomic(d.src_addr); kunmap_atomic(d.src_addr);
if (d.dst_addr) if (d.dst_addr)
kunmap_atomic(d.dst_addr); kunmap_atomic(d.dst_addr);
if (src_pages)
kvfree(src_pages); kvfree(src_pages);
if (dst_pages)
kvfree(dst_pages); kvfree(dst_pages);
return ret; return ret;
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
#define VMWGFX_DRIVER_MINOR 20 #define VMWGFX_DRIVER_MINOR 20
#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
#define VMWGFX_MAX_DISPLAYS 16 #define VMWGFX_NUM_DISPLAY_UNITS 8
#define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768 #define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768
#define VMWGFX_MIN_INITIAL_WIDTH 1280 #define VMWGFX_MIN_INITIAL_WIDTH 1280
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
#define VMWGFX_NUM_GB_CONTEXT 256 #define VMWGFX_NUM_GB_CONTEXT 256
#define VMWGFX_NUM_GB_SHADER 20000 #define VMWGFX_NUM_GB_SHADER 20000
#define VMWGFX_NUM_GB_SURFACE 32768 #define VMWGFX_NUM_GB_SURFACE 32768
#define VMWGFX_NUM_GB_SCREEN_TARGET VMWGFX_MAX_DISPLAYS #define VMWGFX_NUM_GB_SCREEN_TARGET VMWGFX_NUM_DISPLAY_UNITS
#define VMWGFX_NUM_DXCONTEXT 256 #define VMWGFX_NUM_DXCONTEXT 256
#define VMWGFX_NUM_DXQUERY 512 #define VMWGFX_NUM_DXQUERY 512
#define VMWGFX_NUM_MOB (VMWGFX_NUM_GB_CONTEXT +\ #define VMWGFX_NUM_MOB (VMWGFX_NUM_GB_CONTEXT +\
......
...@@ -1283,7 +1283,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, ...@@ -1283,7 +1283,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
{ {
struct drm_device *dev = &dev_priv->drm; struct drm_device *dev = &dev_priv->drm;
struct vmw_framebuffer_surface *vfbs; struct vmw_framebuffer_surface *vfbs;
enum SVGA3dSurfaceFormat format;
struct vmw_surface *surface; struct vmw_surface *surface;
int ret; int ret;
...@@ -1320,34 +1319,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, ...@@ -1320,34 +1319,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
return -EINVAL; return -EINVAL;
} }
switch (mode_cmd->pixel_format) {
case DRM_FORMAT_ARGB8888:
format = SVGA3D_A8R8G8B8;
break;
case DRM_FORMAT_XRGB8888:
format = SVGA3D_X8R8G8B8;
break;
case DRM_FORMAT_RGB565:
format = SVGA3D_R5G6B5;
break;
case DRM_FORMAT_XRGB1555:
format = SVGA3D_A1R5G5B5;
break;
default:
DRM_ERROR("Invalid pixel format: %p4cc\n",
&mode_cmd->pixel_format);
return -EINVAL;
}
/*
* For DX, surface format validation is done when surface->scanout
* is set.
*/
if (!has_sm4_context(dev_priv) && format != surface->metadata.format) {
DRM_ERROR("Invalid surface format for requested mode.\n");
return -EINVAL;
}
vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL); vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL);
if (!vfbs) { if (!vfbs) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -1539,6 +1510,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, ...@@ -1539,6 +1510,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
DRM_ERROR("Surface size cannot exceed %dx%d\n", DRM_ERROR("Surface size cannot exceed %dx%d\n",
dev_priv->texture_max_width, dev_priv->texture_max_width,
dev_priv->texture_max_height); dev_priv->texture_max_height);
ret = -EINVAL;
goto err_out; goto err_out;
} }
...@@ -2225,7 +2197,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, ...@@ -2225,7 +2197,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
struct drm_mode_config *mode_config = &dev->mode_config; struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_vmw_update_layout_arg *arg = struct drm_vmw_update_layout_arg *arg =
(struct drm_vmw_update_layout_arg *)data; (struct drm_vmw_update_layout_arg *)data;
void __user *user_rects; const void __user *user_rects;
struct drm_vmw_rect *rects; struct drm_vmw_rect *rects;
struct drm_rect *drm_rects; struct drm_rect *drm_rects;
unsigned rects_size; unsigned rects_size;
...@@ -2237,6 +2209,8 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, ...@@ -2237,6 +2209,8 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
VMWGFX_MIN_INITIAL_HEIGHT}; VMWGFX_MIN_INITIAL_HEIGHT};
vmw_du_update_layout(dev_priv, 1, &def_rect); vmw_du_update_layout(dev_priv, 1, &def_rect);
return 0; return 0;
} else if (arg->num_outputs > VMWGFX_NUM_DISPLAY_UNITS) {
return -E2BIG;
} }
rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect);
......
...@@ -199,9 +199,6 @@ struct vmw_kms_dirty { ...@@ -199,9 +199,6 @@ struct vmw_kms_dirty {
s32 unit_y2; s32 unit_y2;
}; };
#define VMWGFX_NUM_DISPLAY_UNITS 8
#define vmw_framebuffer_to_vfb(x) \ #define vmw_framebuffer_to_vfb(x) \
container_of(x, struct vmw_framebuffer, base) container_of(x, struct vmw_framebuffer, base)
#define vmw_framebuffer_to_vfbs(x) \ #define vmw_framebuffer_to_vfbs(x) \
......
...@@ -886,6 +886,10 @@ static int vmw_stdu_connector_atomic_check(struct drm_connector *conn, ...@@ -886,6 +886,10 @@ static int vmw_stdu_connector_atomic_check(struct drm_connector *conn,
struct drm_crtc_state *new_crtc_state; struct drm_crtc_state *new_crtc_state;
conn_state = drm_atomic_get_connector_state(state, conn); conn_state = drm_atomic_get_connector_state(state, conn);
if (IS_ERR(conn_state))
return PTR_ERR(conn_state);
du = vmw_connector_to_stdu(conn); du = vmw_connector_to_stdu(conn);
if (!conn_state->crtc) if (!conn_state->crtc)
......
...@@ -2276,9 +2276,12 @@ int vmw_dumb_create(struct drm_file *file_priv, ...@@ -2276,9 +2276,12 @@ int vmw_dumb_create(struct drm_file *file_priv,
const struct SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format); const struct SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
SVGA3dSurfaceAllFlags flags = SVGA3D_SURFACE_HINT_TEXTURE | SVGA3dSurfaceAllFlags flags = SVGA3D_SURFACE_HINT_TEXTURE |
SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_RENDERTARGET |
SVGA3D_SURFACE_SCREENTARGET | SVGA3D_SURFACE_SCREENTARGET;
SVGA3D_SURFACE_BIND_SHADER_RESOURCE |
if (vmw_surface_is_dx_screen_target_format(format)) {
flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE |
SVGA3D_SURFACE_BIND_RENDER_TARGET; SVGA3D_SURFACE_BIND_RENDER_TARGET;
}
/* /*
* Without mob support we're just going to use raw memory buffer * Without mob support we're just going to use raw memory buffer
......
...@@ -58,6 +58,7 @@ int host1x_memory_context_list_init(struct host1x *host1x) ...@@ -58,6 +58,7 @@ int host1x_memory_context_list_init(struct host1x *host1x)
ctx->dev.parent = host1x->dev; ctx->dev.parent = host1x->dev;
ctx->dev.release = host1x_memory_context_release; ctx->dev.release = host1x_memory_context_release;
ctx->dev.dma_parms = &ctx->dma_parms;
dma_set_max_seg_size(&ctx->dev, UINT_MAX); dma_set_max_seg_size(&ctx->dev, UINT_MAX);
err = device_add(&ctx->dev); err = device_add(&ctx->dev);
......
...@@ -625,12 +625,6 @@ static int host1x_probe(struct platform_device *pdev) ...@@ -625,12 +625,6 @@ static int host1x_probe(struct platform_device *pdev)
goto free_contexts; goto free_contexts;
} }
err = host1x_intr_init(host);
if (err) {
dev_err(&pdev->dev, "failed to initialize interrupts\n");
goto deinit_syncpt;
}
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
...@@ -642,6 +636,12 @@ static int host1x_probe(struct platform_device *pdev) ...@@ -642,6 +636,12 @@ static int host1x_probe(struct platform_device *pdev)
if (err) if (err)
goto pm_disable; goto pm_disable;
err = host1x_intr_init(host);
if (err) {
dev_err(&pdev->dev, "failed to initialize interrupts\n");
goto pm_put;
}
host1x_debug_init(host); host1x_debug_init(host);
err = host1x_register(host); err = host1x_register(host);
...@@ -658,13 +658,11 @@ static int host1x_probe(struct platform_device *pdev) ...@@ -658,13 +658,11 @@ static int host1x_probe(struct platform_device *pdev)
host1x_unregister(host); host1x_unregister(host);
deinit_debugfs: deinit_debugfs:
host1x_debug_deinit(host); host1x_debug_deinit(host);
host1x_intr_deinit(host);
pm_put:
pm_runtime_put_sync_suspend(&pdev->dev); pm_runtime_put_sync_suspend(&pdev->dev);
pm_disable: pm_disable:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
host1x_intr_deinit(host);
deinit_syncpt:
host1x_syncpt_deinit(host); host1x_syncpt_deinit(host);
free_contexts: free_contexts:
host1x_memory_context_list_free(&host->context_list); host1x_memory_context_list_free(&host->context_list);
......
...@@ -466,6 +466,7 @@ struct host1x_memory_context { ...@@ -466,6 +466,7 @@ struct host1x_memory_context {
refcount_t ref; refcount_t ref;
struct pid *owner; struct pid *owner;
struct device_dma_parameters dma_parms;
struct device dev; struct device dev;
u64 dma_mask; u64 dma_mask;
u32 stream_id; u32 stream_id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment