Files
2024-06-17 20:18:01 +08:00

290 lines
7.9 KiB
C

/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2020 Loongson Corporation
*
* 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS 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.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*/
/*
* Authors:
* Sui Jingfeng <suijingfeng@loongson.cn>
*/
#ifndef __LSDC_DRV_H__
#define __LSDC_DRV_H__
#include <drm/drm_device.h>
#include <drm/drm_crtc.h>
#include <drm/drm_plane.h>
#include <drm/drm_encoder.h>
#include <drm/drm_connector.h>
#include <drm/drm_bridge.h>
#define LSDC_NUM_CRTC 2
#define LSDC_CLUT_SIZE 256
enum loongson_dc_family {
LSDC_CHIP_UNKNOWN = 0,
LSDC_CHIP_2K1000 = 1, /* 2-Core SoC, 64-bit */
LSDC_CHIP_7A1000 = 2, /* North bridges */
LSDC_CHIP_7A1000_PLUS = 3, /* bandwidth improved */
LSDC_CHIP_2K0500 = 4, /* Reduced version of 2k1000, single core */
LSDC_CHIP_7A2000 = 5, /* North bridges */
LSDC_CHIP_LAST,
};
/* SoC parameters and platform specific information */
struct lsdc_platform_desc {
enum loongson_dc_family chip;
uint32_t num_of_crtc;
uint32_t max_pixel_clk;
uint32_t max_width;
uint32_t max_height;
uint32_t num_of_hw_cursor;
uint32_t hw_cursor_w;
uint32_t hw_cursor_h;
bool has_builtin_i2c;
bool has_vram;
bool broken_gamma;
};
struct lsdc_connector {
struct drm_connector base;
struct i2c_adapter *ddc;
unsigned char edid_data[EDID_LENGTH];
bool has_edid;
struct display_timings *disp_tim;
bool has_disp_tim;
bool always_connected;
};
#define to_lsdc_connector(x) \
container_of(x, struct lsdc_connector, base)
/*
* PLL structure
*
* L1 Fref Fvco L2
* refclk +-----------+ +------------------+ +---------+ outclk
* -------> | Prescaler | ---> | Clock Multiplier | ---> | divider | --------->
* | +-----------+ +------------------+ +---------+ ^
* | ^ ^ ^ |
* | | | | |
* | | | | |
* | div_ref loopc div_out |
* | |
* +-------------------------- sel_out -------------------------------+
*
*
* outclk = refclk / div_ref * loopc / div_out;
*
* PLL working requirement:
*
* 1) 20 MHz <= refclk / div_ref <= 40Mhz
* 2) 1.2 GHz <= refclk /div_out * loopc <= 3.2 Ghz
*
*/
struct lsdc_pll;
struct lsdc_pll_core_values {
unsigned int div_ref;
unsigned int loopc;
unsigned int div_out;
};
struct lsdc_pixpll_funcs {
void (*init)(struct lsdc_pll * const this, u32 id);
bool (*find_pll_param)(struct lsdc_pll * const this, unsigned int clk);
int (*compute_clock)(struct lsdc_pll * const this, unsigned int clk);
int (*config_pll)(struct lsdc_pll * const this);
/* dump all pll related paramenter, debug purpose */
int (*print_clock)(struct lsdc_pll * const this, unsigned int pixclk);
unsigned int (*get_clock_rate)(struct lsdc_pll * const this,
struct lsdc_pll_core_values *pout);
};
struct lsdc_pll {
const struct lsdc_pixpll_funcs *funcs;
struct drm_device *ddev;
unsigned int ref_clock; /* kHz */
u32 reg_base;
u32 reg_size;
void __iomem *mmio;
unsigned short index;
unsigned short div_out;
unsigned short loopc;
unsigned short div_ref;
};
/*
* struct lsdc_display_pipe - Abstraction of hardware display pipeline.
* @crtc: CRTC control structure
* @primary: Framebuffer plane control structure
* @cursor: Framebuffer plane control structure
* @encoder: Encoder control structure
* @pixpll: Pll control structure
* @lconn: connector control structure
* @output: point to output control structure of the display pipe
* @index: the index corresponding to the hardware display pipe
* @hw_clone: true if this display pipe working at hardware cloning mode.
* @available: is this display pipe is available on the motherboard, The
* downstream mother board manufacturer may use only one of them.
* For example, LEMOTE LX-6901 board has only one VGA output.
*/
struct lsdc_display_pipe {
struct drm_crtc crtc;
struct drm_plane primary;
struct drm_plane cursor;
struct lsdc_pll pixpll;
struct drm_encoder encoder;
/* There is only a 1:1 mapping of encoders and connectors for lsdc */
struct lsdc_connector *lconn;
int index;
bool hw_clone;
bool available;
};
static inline struct lsdc_display_pipe *
drm_crtc_to_dispipe(struct drm_crtc *crtc)
{
return container_of(crtc, struct lsdc_display_pipe, crtc);
}
static inline struct lsdc_display_pipe *
lsdc_cursor_to_dispipe(struct drm_plane *plane)
{
return container_of(plane, struct lsdc_display_pipe, cursor);
}
static inline struct lsdc_display_pipe *
lsdc_primary_to_dispipe(struct drm_plane *plane)
{
return container_of(plane, struct lsdc_display_pipe, primary);
}
struct lsdc_device {
struct drm_device ddev;
void __iomem *reg_base;
void __iomem *vram;
resource_size_t vram_base;
resource_size_t vram_size;
unsigned int num_output;
struct lsdc_display_pipe dispipe[LSDC_NUM_CRTC];
/* platform specific data */
const struct lsdc_platform_desc *desc;
/* @reglock: protects concurrent register access */
spinlock_t reglock;
/*
* @dirty_lock: Serializes framebuffer flushing
*/
struct mutex dirty_lock;
int irq;
u32 irq_status;
/*
* @shadowfb: is shadow fb layer is enabled.
*/
bool shadowfb;
/*
* @ddc0: false if ddc0 is disabled.
*/
bool ddc0;
/*
* @ddc1: false if ddc1 is disabled.
*/
bool ddc1;
/*
* @enable_gamma: true if hardware gamma is desired.
*/
bool enable_gamma;
/*
* @has_of_graph: true if there are OF graph in the DT
*/
bool has_of_graph;
};
static inline struct lsdc_device *to_lsdc(struct drm_device *drm)
{
return container_of(drm, struct lsdc_device, ddev);
}
int lsdc_mode_config_init(struct lsdc_device *ldev);
void lsdc_mode_config_fini(struct lsdc_device *ldev);
void lsdc_fb_dirty_update_impl(void __iomem *dst,
void *vaddr,
struct drm_framebuffer * const fb,
struct drm_clip_rect * const clip);
int lsdc_crtc_init(struct drm_device *ddev,
unsigned int index,
struct drm_crtc *crtc,
struct drm_plane *fb_plane,
struct drm_plane *cursor_plane);
int lsdc_plane_init(struct drm_device *ddev,
struct drm_plane *plane,
enum drm_plane_type type,
unsigned int index);
int lsdc_init_pix_pll(struct drm_device *ddev,
struct lsdc_pll *pixpll,
unsigned int index);
int lsdc_encoder_init(struct drm_device *ddev,
struct drm_encoder *encoder,
unsigned int index);
struct lsdc_connector *
lsdc_create_connector(struct drm_device *ddev, unsigned int index);
int lsdc_attach_bridges(struct lsdc_device *ldev, unsigned int num_crtc);
extern int lsdc_shadowfb;
extern struct drm_driver lsdc_drm_driver;
extern struct platform_driver lsdc_platform_driver;
#ifdef CONFIG_DRM_LSDC_PCI_DRIVER
extern struct pci_driver lsdc_pci_driver;
#endif
#endif