1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include <ddk/protocol/display-controller.h>
8#include <ddktl/device.h>
9#include <hwreg/mmio.h>
10#include <region-alloc/region-alloc.h>
11#include <lib/zx/vmo.h>
12
13#include "gtt.h"
14#include "pipe.h"
15#include "power.h"
16#include "registers-ddi.h"
17#include "registers-pipe.h"
18#include "registers-transcoder.h"
19
20namespace i915 {
21
22class Controller;
23class DisplayDevice;
24
25// Thread safe weak-ref to the DisplayDevice, because the backlight device
26// lifecycle is managed by devmgr but the DisplayDevice lifecycle is managed
27// by the display controller class.
28typedef struct display_ref {
29    mtx_t mtx;
30    DisplayDevice* display_device __TA_GUARDED(mtx);
31} display_ref_t;
32
33
34class DisplayDevice {
35public:
36    DisplayDevice(Controller* device, uint64_t id, registers::Ddi ddi);
37    virtual ~DisplayDevice();
38
39    bool AttachPipe(Pipe* pipe);
40    void ApplyConfiguration(const display_config_t* config);
41
42    // Query whether or not there is a display attached to this ddi. Does not
43    // actually do any initialization - that is done by Init.
44    virtual bool Query() = 0;
45    // Does display mode agnostic ddi initialization - subclasses implement InitDdi.
46    bool Init();
47    // Initializes the display backlight for an already initialized display.
48    void InitBacklight();
49    // Resumes the ddi after suspend.
50    bool Resume();
51    // Loads ddi state from the hardware at driver startup.
52    void LoadActiveMode();
53    // Method to allow the display device to handle hotplug events. Returns
54    // true if the device can handle the event without disconnecting. Otherwise
55    // the device will be removed.
56    virtual bool HandleHotplug(bool long_pulse) { return false; }
57
58    uint64_t id() const { return id_; }
59    registers::Ddi ddi() const { return ddi_; }
60    Controller* controller() { return controller_; }
61
62    virtual uint32_t i2c_bus_id() const = 0;
63
64    Pipe* pipe() const { return pipe_; }
65
66    bool is_hdmi() const { return is_hdmi_; }
67    void set_is_hdmi(bool is_hdmi) { is_hdmi_ = is_hdmi; }
68
69    virtual bool HasBacklight() { return false; }
70    virtual void SetBacklightState(bool power, uint8_t brightness) {}
71    virtual void GetBacklightState(bool* power, uint8_t* brightness) {}
72
73    virtual bool CheckPixelRate(uint64_t pixel_rate) = 0;
74protected:
75    // Attempts to initialize the ddi.
76    virtual bool InitDdi() = 0;
77    virtual bool InitBacklightHw() { return false; }
78
79    // Configures the hardware to display content at the given resolution.
80    virtual bool DdiModeset(const display_mode_t& mode,
81                            registers::Pipe pipe, registers::Trans trans) = 0;
82    virtual bool ComputeDpllState(uint32_t pixel_clock_10khz, struct dpll_state* config) = 0;
83    // Load the clock rate from hardware if it's necessary when changing the transcoder.
84    virtual uint32_t LoadClockRateForTranscoder(registers::Trans transcoder) = 0;
85
86    // Attaching a pipe to a display or configuring a pipe after display mode change has
87    // 3 steps. The second step is generic pipe configuration, whereas PipeConfigPreamble
88    // and PipeConfigEpilogue are responsible for display-type-specific configuration that
89    // must be done before and after the generic configuration.
90    virtual bool PipeConfigPreamble(const display_mode_t& mode,
91                                    registers::Pipe pipe, registers::Trans trans) = 0;
92    virtual bool PipeConfigEpilogue(const display_mode_t& mode,
93                                    registers::Pipe pipe, registers::Trans trans) = 0;
94
95    hwreg::RegisterIo* mmio_space() const;
96
97private:
98    bool CheckNeedsModeset(const display_mode_t* mode);
99
100    // Borrowed reference to Controller instance
101    Controller* controller_;
102
103    uint64_t id_;
104    registers::Ddi ddi_;
105
106    Pipe* pipe_= nullptr;
107
108    PowerWellRef ddi_power_;
109
110    bool inited_ = false;
111    display_mode_t info_ = {};
112    bool is_hdmi_ = false;
113
114    zx_device_t* backlight_device_ = nullptr;
115    display_ref_t* display_ref_ = nullptr;
116};
117
118} // namespace i915
119